以下是最常见的代码形式,其中的标记是需要注意的细节:
1、为什么这个算法能够找到右侧边界?
答:类似地,关键点还是这里:
当 nums[mid] == target
时,不要立即返回,而是增大「搜索区间」的左边界 left
,使得区间不断向右靠拢,达到锁定右侧边界的目的。
2、为什么最后返回 left - 1
而不像左侧边界的函数,返回 left
?而且我觉得这里既然是搜索右侧边界,应该返回 right
才对。
答:首先,while 循环的终止条件是 left == right
,所以 left
和 right
是一样的,你非要体现右侧的特点,返回 right - 1
好了。
至于为什么要减一,这是搜索右侧边界的一个特殊点,关键在锁定右边界时的这个条件判断:
因为我们对 left
的更新必须是 left = mid + 1
,就是说 while 循环结束时,nums[left]
一定不等于 target
了,而 nums[left-1]
可能是 target
。
至于为什么 left
的更新必须是 left = mid + 1
,当然是为了把 nums[mid]
排除出搜索区间,这里就不再赘述。
3、为什么没有返回 -1 的操作?如果 nums
中不存在 target
这个值,怎么办?
答:只要在最后判断一下 nums[left-1]
是不是 target
就行了,类似之前的左侧边界搜索,做一点额外的判断即可:
4、是否也可以把这个算法的「搜索区间」也统一成两端都闭的形式呢?这样这三个写法就完全统一了,以后就可以闭着眼睛写出来了。
答:当然可以,类似搜索左侧边界的统一写法,其实只要改两个地方就行了:
当然,由于 while 的结束条件为 right == left - 1
,所以你把上述代码中的 left - 1
都改成 right
也没有问题,这样可能更有利于看出来这是在「搜索右侧边界」
最后,奉上大佬的代码可视化
我写了首诗,把二分搜索算法变成了默写题 | labuladong 的算法笔记
最后,总结我们前面学习的二分算法细节问题: 4. 逻辑统一