关于二分法的一些误区
以前刷算法题的时候刷到二分查找,会被告知二分查找的一些固定写法,今天刷了几道leetcode,总结一下。
最简单的二分查找问题可以参见leetcode链接
简单叙述就是,在一个有序数组nums中查找某个值target,找到的话返回该target在nums中的下标,找不到则返回-1
以下是摘自另一篇博客的“标准”写法:
/**
* 二分查找,找到该值在数组中的下标,否则为-1
*/
static int binarySerach(int[] array, int key) {
int left = 0;
int right = array.length - 1;
// 这里必须是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] == key) {
return mid;
}
else if (array[mid] < key) {
left = mid + 1;
}
else {
right = mid - 1;
}
}
return -1;
}
上述代码的正确性朋友们可以自行验证,但是有几个问题:
1. while停止条件必须是low <= high吗?
2. 每次更新low或者high指针时必须用low = mid + 1和high = mid - 1吗?
解答:
1. 关于while的停止条件,其实并不一定是low <= high。个人理解:low和high指针只是限制了一个查找范围。
可以证明:
当low < high - 1,mid = low + (high - low) / 2 时,始终有low < mid < high成立。
所以,while循环体内mid的搜索范围为任何介于nums[low]和nums[high]的元素。
通过不断更新low或者high的值,我们不断将搜索范围缩小,直到nums[low]和nums[high]之间不包含任何元素,此时我们跳出循环。此时,nums[low]和nums[high]两者之间必定包含了我们要找的值,只要分别比较两者和target即可。
2. 在while中更新low或者high指针时,必须使用low = mid + 1或者high = mid - 1吗?
也不一定,从程序逻辑可以看出,只有在nums[mid] != target时,我们才会更新low或者high指针,而此时,将不将mid排除在搜索范围之内其实意义不大(或者说没有区别)。
最后,朋友们如果对二分查找感觉不是很熟练的话,可以刷一下LeetCode上关于binary search的题目(传送门),我自己也正在刷题中,共勉。
以上。
上一篇: 算法图解(选择排序)
下一篇: Search for a Range