使用二分法的前提条件
1.数组为有序数组
2.数组中无重复元素
因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的。
二分查找边界问题
到底是 while(left < right) 还是 while(left <= right)
到底是right = middle呢,还是要right = middle - 1呢?
二分法有很多版本,主要是因为对区间的定义没有想清楚,区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。
#而
二分查找的两种写法
左闭右闭即[left, right]
- while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
- if (nums[middle] > target) right 要赋值为 middle -
1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
var search = function(nums, target) {
var left=0;
var right=nums.length-1;
var middle;
while(left<=right){
//因为js语言的特性,两个整数相除若是小数,则还是输出小数,所以我们要把他取整,向下取整和向上取整都是可以的。
middle=Math.floor((left+right)/2);
if(nums[middle]>target){
right=middle-1;
}else if(nums[middle]<target){
left=middle+1;
}else{
return middle;
}
}
return -1;
};
如果说定义 target 是在一个在左闭右开的区间里,也就是[left, right) ,那么二分法的边界处理方式则截然不同。
- while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的
- if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]
var search = function(nums, target) {
var left=0;
//不同
var right=nums.length;
var middle;
while(left<right){
//因为js语言的特性,两个整数相除若是小数,则还是输出小数,所以我们要把他取整,向下取整和向上取整都是可以的。
middle=Math.floor((left+right)/2);
if(nums[middle]>target){
right=middle;
}else if(nums[middle]<target){
left=middle+1;
}else{
return middle;
}
}
return -1;
};
在使用二分法时,我们应该确定边界条件的问题,理解边界区间代表的含义,确定好一种方法,不要把两种方法混淆。