刷题模板 | 二分查找

在leetcode上看到有人分享二分的模板,特此总结。

作者:liweiwei1419
链接:https://leetcode-cn.com/problems/search-insert-position/solution/te-bie-hao-yong-de-er-fen-cha-fa-fa-mo-ban-python-/
 

适用条件:

有“排序数组”、“有序数列”等,基本都在暗示适用二分

中间数索引:

一般写作 int mid = (left + right) / 2;

但是这种写法在left和right很大的时候容易越界。

  • 写作 int mid = left + (right - left) / 2;
  • 或者 int mid = (left + right) >>> 1; (无符号右移)

左中位数:int mid = left + (right - left) / 2 ; 

右中位数:int mid = left + (right - left + 1) / 2 ;

循环条件:

一般写作 while(left <= right);

但是这种写法需要考虑最后到底返回左还是右

  • 直接写成 while(left < right); 这样退出循环的时候一定有left == right,不用再考虑到底返回哪个(因为都一样)

分支逻辑:

  • 永远先写逻辑上容易想到的,这个逻辑一般也是排除中位数的逻辑。

例如:实现 int sqrt(int x) 函数。计算并返回 x 的平方根,其中 x 是非负整数。

此时,因为题目中说“返回类型是整数,结果只保留整数的部分,小数部分将被舍去”。例如 5的平方根约等于 2.236,在这道题应该返回 2。因此如果一个数的平方小于或者等于 x,那么这个数有可能是也有可能不是 x 的平方根,但是能很肯定的是,如果一个数的平方大于 x ,这个数肯定不是 x 的平方根。

注意:先写“好想”的分支,排除了中位数之后,通常另一个分支就不排除中位数,而不必具体考虑另一个分支的逻辑的具体意义,且代码几乎是固定的。

if(x*x > num) {
    right = mid - 1;
}
else {
    left = mid;
}

根据分支逻辑选择中位数的类型(左中位数还是右中位数)

左中位数还是右中位数选择的标准根据分支的逻辑而来,标准是每一次循环都应该让区间收缩,当候选区间只剩下 22 个元素的时候,为了避免死循环发生,选择正确的中位数类型。如果你实在很晕,不防就使用有 22 个元素的测试用例,就能明白其中的原因,另外在代码出现死循环的时候,建议你可以将左边界、右边界、你选择的中位数的值,还有分支逻辑都打印输出一下,出现死循环的原因就一目了然了。

二分查找模板-1.png

二分查找模板-2.png

退出循环的时候要判断mid是否被更新了!

详见剑指offer第六题(旋转数组的最小数字)

后处理

最后要判断这时候的arr[left]是不是你要的,(主要是有可能k就不在该数组的情况),适当调节返回值(剑指第37题)

发布了53 篇原创文章 · 获赞 5 · 访问量 1529

猜你喜欢

转载自blog.csdn.net/zhicheshu4749/article/details/103086361