zoukankan      html  css  js  c++  java
  • 二分算法(以 数的范围 为例)

    原题:

    给定一个按照升序排列的长度为n的整数数组,以及 q 个查询。

    对于每个查询,返回一个元素k的起始位置和终止位置(位置从0开始计数)。

    如果数组中不存在该元素,则返回“-1 -1”。

    输入格式
    第一行包含整数n和q,表示数组长度和询问个数。

    第二行包含n个整数(均在1~10000范围内),表示完整数组。

    接下来q行,每行包含一个整数k,表示一个询问元素。

    输出格式
    共q行,每行包含两个整数,表示所求元素的起始位置和终止位置。

    如果数组中不存在该元素,则返回“-1 -1”。

    数据范围
    1≤n≤100000
    1≤q≤10000
    1≤k≤10000

    输入样例:
    6 3
    1 2 2 3 3 4
    3
    4
    5
    输出样例:
    3 4
    5 5
    -1 -1

    整数二分

    首先寻找下界,先定义一个 mid = (l+r) >> 1 ,即如果找到了符合条件的 q[mid] ,则可知符合条件的下界坐标在 [x, q[mid]] 的范围内,注意是闭区间,所以这时候更新上界 r = mid ,否则 l = mid+1

    寻找上界,同样是先定义一个 mid = (l+r) >> 1,如果找到了符合条件的 q[mid] ,则可知符合条件的上界坐标在 [q[mid], x] ,所以这时候要更新下界 l = mid ,否则 r = mid-1 ,最重要的一定就是,当发现更新的是 l = mid 的时候,一定要注意 mid = (l+r+1) >> 1 需要这样更改,否则会造成边界问题,进入死循环。

    所以二分有两个重要的模板:

    bool check(int x) { }; //检查x是否具有某种性质
    void bsearch_1(int l, int r)
    {
        while(l < r)
        {
            int mid = (l+r) >> 1;
            if(check(mid)) r = mid;
            else l = mid+1;
        }
        return l;
    }
    
    void bsearch_2(int l, int r)
    {
        while(l < r)
        {
            int mid = (l+r+1) >> 1;
            if(check(mid)) l = mid;
            else r = mid-1;
        }
        return l;
    }
    

    需要注意区别使用。

    本题的AC代码

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    const int N = 100010;
    int q[N];
    
    int main()
    {
        int n, m;
        cin >> n >> m;
        for(int i = 0; i < n; i++) cin >> q[i];
    
        while(m--)
        {
            int x;
            scanf("%d", &x);
    
            int l = 0, r = n-1;
            while(l < r)
            {
                int mid = (l+r) >> 1;
                if(q[mid] >= x) r = mid;
                else l = mid+1;
            }
            if(q[l] != x) cout << "-1 -1" << endl;
            else
            {
                cout << l << " ";
    
                int l = 0, r = n-1;
                while(l < r)
                {
                    int mid = (l+r+1) >> 1;
                    if(q[mid] <= x) l = mid;
                    else r = mid-1;
                }
    
                cout << l << " ";
            }
        }
        system("pause");
        return 0;
    }
    

    浮点数的二分(以寻找一个数的平方根为例)
    因为浮点数可以严格的除以2,所以不用考虑边界问题了,让所区间非常小时我们认为边界即答案,还有就是边界的数量级最好比所得结果所保留小数的位数多两位,例如保留六位小数,最好 r-l > 1e-8

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    double maxn(double a, double b)
    {
        if(a > b) return a;
        return b;
    }
    
    int main()
    {
        double n;
    
        cin >> n;
        double l = 0, r = maxn(1, n);
        while(r-l > 1e-8)
        {
            double mid = (l+r)/2;
            if(mid*mid >= n) r = mid;
            else l = mid;
        }
        printf("%llf", l);
        system("pause");
        return 0;
    }
    

    寻找一个数的三次方根

    #include <iostream>
    using namespace std;
    
    int main()
    {
        double x;
    
        cin >> x;
        double l = -10000, r = 10000;
        while(r - l >= 1e-8)
        {
            double mid = (l+r)/2;
            if(mid*mid*mid >= x) r = mid;
            else l = mid;
        }
        printf("%lf
    ", l);
        system("pause");
        return 0;
    }
    
  • 相关阅读:
    SpringMvc的服务器端跳转和客户端跳转
    springMvc的一些简介 和基于xml的handlerMapping基本流程
    springMvc 的参数验证 BindingResult result 的使用
    SpringMVC 学习笔记(二) @RequestMapping、@PathVariable等注解
    springmvc处理ajax请求
    取maven copy部分
    maven scope含义的说明
    Maven依赖中的scope详解
    EasyMock 使用方法与原理剖析
    Maven:Generating Project in Batch mode 卡住问题
  • 原文地址:https://www.cnblogs.com/ZhengLijie/p/13399605.html
Copyright © 2011-2022 走看看