数组: 总结了二分查找的通用模板写法, 彻底解决几个易混淆问题, 力扣35:搜索插入位置

Posted 一起学计算机

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数组: 总结了二分查找的通用模板写法, 彻底解决几个易混淆问题, 力扣35:搜索插入位置相关的知识,希望对你有一定的参考价值。






此专栏文章是对力扣上算法题目各种方法总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解.


目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), 毕竟算法不是做了一遍就能完全记住的. 所以本文适合已经知道解题思路和方法, 想进一步加强理解和记忆的朋友, 并不适合第一次接触此题的朋友(可以根据题号先去力扣看看官方题解, 然后再看本文内容).


关于本专栏所有题目的目录链接, 刷算法题目的顺序/注意点/技巧, 以及思维导图源文件问题请点击. 导图中源码在文章最后. 文末B站同步更新算法视频讲解.

0.导图整理

1.先确定查找区间的左右开闭情况

这是写二分查找最根本的问题, 因为根据不同的情况, 下面的操作是完全不同的, 这也是很多朋友感觉二分查找难写的地方, 这里为了方便, 我直接将区间定义为左闭右开[left, right)的形式, 这里根据自己的习惯最好将区间完全固定住, 以后都按照一种模式来写, 如果你习惯左闭右闭也同样固定住, 这样不用每次都纠结.


固定为左闭右开的好处是: 很多函数中对区间的操作都是左闭右开的形式, 这算是语言的特点吧, 比如字符串中截取子串长度, 列表的截取都是左闭右开的形式, 这样就可以和语言特点相对应.


另一个好处就是在返回值的问题上, 下文会提到.


2.数组长度

当区间固定住为左闭右开, 数组长度就固定为[0, len(nums)), 这也是左右端点的初值, 如为左闭右闭, 那长度就是[0, len(nums)-1]了.


3.循环退出条件

这里也要特别注意, 代码为 while left < right 因为区间是右开, 所以不能有=, 否则区间就不存在了, 这样写循环控制的另外一个好处就是在退出循环时, 必然满足 left == right, 这样在最后的返回值就可以任意返回了, 因为它们完全相等, 而不用去纠结该返回哪个端点了.


4.中间值的写法

写法为 mid = left + (right - left)//2 , //2在Python中表示整除/2在Python中表示正常除, 是有余数的, 这点和其他语言有所不同. 这样写的好处也非常简单, 就是为了防止大数溢出, 因为写成(left + right)//2时, 当数比较大时, left + right是有溢出的风险的, 这种写法就可以避免了.


5.中间值和目标值的比较关系

if nums[mid] < target  这个比较关系涉及到上图中4和5的两种变形, 写成什么样的形式是不固定的, 这里是根据题目要求来写的. 


简单来说就是如果是<, 那么当nums[mid]达到是比target小的数中的最大的数的时候, 通过if条件进入, left的值为mid+1后的值必然是大于等于target的值, 这时候可能取到和target相等的位置.


但是当换成时, 当nums[mid] == target时, 仍然会进入if条件, left的值为mid+1后的值必然是大于target的值, 这时候就不可能取到和target相等的位置. 就会收敛到第一个大于target的位置


这点还是有点复杂的, 可以好好多看几遍.


第5条是说数组由递增改为递减, 其实只要将判断条件反过来就可以了, 还是很好理解的.


6.左右区间的变化

区间的变化完全取决于区间的定义, 因为左闭, 所以左区间为left = mid+1, 因为右开, 所以右区间变换为right = mid, 其实真实取的值也就是mid-1


7.最终返回值

最后的返回值上文已经说过了, 随便返回哪个都可以.


这个模板算是比较好记忆, 也比较简洁的模板了, 如果你也比较习惯左闭右开的区间, 直接理解记住此模板就可以了, 如果你习惯左闭右闭的区间, 那稍微更改下也就可以了.


源码

class Solution: def searchInsert(self, nums: List[int], target: int) -> int: left, right = 0, len(nums) #采用左闭右开区间[left,right) while left < right: # 右开所以不能有=,区间不存在 mid = left + (right - left)//2 # 防止溢出, //表示整除 if nums[mid] < target: # 中点小于目标值,在右侧,可以得到相等位置 left = mid + 1 # 左闭,所以要+1 else: right = mid # 右开,真正右端点为mid-1 return left # 此算法结束时保证left = right,返回谁都一样

数组: 总结了二分查找的通用模板写法, 彻底解决几个易混淆问题, 力扣35:搜索插入位置

以下内容可点击 链接 查看相关系列文章: 
点击

【阅读原文】直达B站







  

点个赞 点个在看你最好看

以上是关于数组: 总结了二分查找的通用模板写法, 彻底解决几个易混淆问题, 力扣35:搜索插入位置的主要内容,如果未能解决你的问题,请参考以下文章

力扣35:搜索插入位置, 总结了二分查找的通用模板写法, 彻底解决几个易混淆问题

算法二分法 ② ( 排序数组中查找目标值 | 二分法的经典写法 | 在排序数组中查找元素的最后一个位置 | 二分法的通用模板 )

二分查找总结及部分Lintcode题目分析 1

二分查找总结

二分算法(java超详细)

有序数组二分查找模板