二分法

  1. 首先找到数组(有序数组)中 的中间值,mid=(left+right)>>1,区间[left, right]被划分成[left, mid]和[mid + 1, right];如果是mid = l + r + 1 >> 1,区间[left, right]被划分成[left, mid - 1]和[mid, right]。

  2. 然后通过check(mid)判断中间值是不是满足这个性质,check是根据不同的题型编写的。

  3. 最后就能使用折半,缩小区间了,如果区间缩到了1,那么那个也就是答案。

    注意 二分的本质不是单调性,如果有单调性,一定可以二分,但是可以二分的题目,不一定有单调性。

    二分的本质,问题一半满足,一半不满足,可以寻找到边界,这个边界可以将数组分为两个部分。因为整数边界必须做出选择,代码将有两个模板。而浮点数不是。

    二分法应首先更具问题想出来 判断条件。如果判断条件是上图中第一种方式 则应该写成l + r + 1;如果是第二种,写成l + r;

    给定一个按照升序排列的长度为n的整数数组,以及 q 个查询。
    
    对于每个查询,返回一个元素k的起始位置和终止位置(位置从0开始计数)。
    
    如果数组中不存在该元素,则返回“-1 -1”。
    #include<iostream>
    using namespace std;
    const int N = 100010;
    
    int n, q, a[N];
    
    int bearch_l(int l, int r, int k)
    {
        while(l < r)
        {
            int mid = l + r >> 1;
            if(a[mid] >= k) r = mid;
            else l = mid + 1;
        }
        return k == a[l] ? l : -1; 
    }
    
    int bearch_r(int l, int r, int k)
    {
        while(l < r)
        {
            int mid = l + r + 1 >> 1;
            if(a[mid] <= k) l = mid;
            else r = mid - 1;
        }
        return k == a[l]? l : -1;
    }
    
    int main()
    {
        cin >> n >> q;
        for(int i = 0; i < n; i++) scanf("%d", &a[i]);
        
        while(q--)
        {
            int k; 
            cin >> k;
            cout << bearch_l(0, n-1, k) << ' ';
            cout << bearch_r(0, n-1, k) << endl;
        }
        return 0;
    }

     

posted @ 2020-09-04 19:23  F_jin  阅读(277)  评论(0)    收藏  举报