lower_bound二分的三种写法

STL里lower_bound和upper_bound都是找元素的插入位置,区别在于如果插入的值在数组中已经存在,这个插入位置有2种选择,可以插到第一个位置,也可以插到最后一个相同元素后面的位置,也就是插到头部还是尾部的区别。lower_bound是插到头部,upper_bound是append到后面。如果数组里没有和插入值相同的元素,lower_bound和upper_bound的结果是一样的。


给定一个排序数组和一个数target,找出target在数组中第一次出现的位置,如不存在返回-1

写法一:

int binarySearch(vector<int> &array, int target) {
        int l = 0, r = array.size() - 1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if (array[mid] < target) l = mid+1;
            else r = mid-1;
        }
        return l < array.size() && array[l] == target ? l : -1;
    }

关键点:

1)循环条件 l <= r,和标准二分一样。

2)  target == array[mid] 的情况也是 r = mid - 1,没有r=mid 或 l = mid 的分支,保证循环一定可以退出。

3)此算法思路是当target == array[mid]时候区间右端也排除mid,当mid左边仍然有等于target的元素时,第一个等于target的位置仍在区间里;当第一个等于target的位置(即所求)也被排除,问题变为在[l, mid - 1]里找target的插入位置,显然是在末尾之后,即mid。

4)为什么最后是a[l]而不是a[r]? 因为当只剩一个元素l==r的时候, 如果 target比之大,插入位置就是这个位置后面一个位置,即执行了l = mid + 1之后的l;如果target 比之小,那么target应该取代当前元素的位置,还是l

总结:本质上是找lower_bound插入位置,最后的判断:如果插入位置在数组范围,且等于插入位置,则存在元素。

写法二:

int binarySearch(vector<int> &array, int target) {
        int l = 0, r = array.size() - 1;
        while (l < r) {
            int mid = l + (r - l) / 2;
            if (target <= array[mid]) r = mid;
            else l = mid + 1;
        }
        return array[l] == target ? l : -1;
    }


1)循环条件l < r

2) invariant property: 如果target在数组里,则一定在区间[l, r]里,当target == array[mid]时,新区间的右端要包括mid,即r = mid。注意这里利用了这一情况:当区间只有2个元素的时候mid指向的是左边的元素l,即不会是r,故r = mid 不会造成死循环

3)循环退出时候,要么l>r, 是一个空区间,说明不存在target;要么l == r, 是一个只有一个元素的区间,要么这个元素就是target,要么不存在target.

写法三:

int binarySearch(vector<int> &array, int target) {
        int l = 0, r = array.size() - 1;
        while (l < r - 1) {
            int mid = l + (r - l) / 2;
            if (target <= array[mid]) r = mid;
            else l = mid + 1;
        }
        if (array[l] == target) return l;
        if (array[r] == target) return r;
        return -1;
    }

1)循环条件 l < r - 1,也就是循环执行的条件是数组至少有三个元素,这样的好处是mid 不会是l或者r中任意一个,不论是令l = mid 或者 r = mid都不会死循环。

2)invariant property: 如果数组里有target, 则一定在区间[l, r]里。

3)循环退出时候,要么l和r相邻要么l == r,先判断array[l]是不是target, 如果是l就是所求;否则再判断array[r]是不是target, 如果是返回r; 如果以上两种情况都不是,说明target不存在,返回-1。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值