704 二分查找
二分法属于区间查找,需要顺序排序。这里有两种做法,一种左闭右开,一种左开右闭。循环不变量。
重点有两点:
- while循环区间循环有意义。比如[1,1]这种区间是正常的,但是[1,1)这种区间就不正确;影响到while条件的<号取值
- if判断的时候,mid已经比较过了,所以循环不变量的赋值要看left、right是闭区间还是开区间;闭区间因为已经比较过,所以mid±1;开区间由于不包含可以直接赋值mid
方法一:左闭右闭(推荐)
public int search01(int[] nums, int target) {
/**
* 找出中间数 [) []
* 比大小
* 更新左边 或者 更新右边
*/
int left = 0;
int right = nums.length - 1;
// 左闭右闭 (1. 区间必须有意义 2.更新数值具体分析)
// while循环区间不断查找,区间循环不变量right left,因为闭区间[1,1]存在意义,所以《=
while (left <= right) {
int mid = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
//说明在左边,要更新右边的值
if (target < nums[mid]) {
//由于右边是闭区间,已经比较过,所以取前一位继续比较
right = mid - 1;
} else if (target > nums[mid]) {
//目标值在右边,更新左边,左边是闭区间,已经比较过了,所以+1
left = mid + 1;
} else {
//相等直接返回
return mid;
}
}
return -1;
}
方法二:左闭右开
// 左闭右开
public int search(int[] nums, int target) {
int left = 0, right = nums.length;//由于是左闭有开区间,所以左边多一位,才能全部包括
while (left < right) { //因为【1,1)这种区间不存在意义,所以必须是 <
int mid = (right + left) / 2;
if ( target < nums[mid] ) { // 目标值 小于 中间数,更新右边值
right = mid; //因为刚才已经比较过mid值了,所以这次就不比较了,开区间不包含
} else if (target > nums[mid]) { // 大于中间数,更新左边
left = mid + 1; //左边是闭区间,所以需要+1
} else {
return mid;
}
}
return -1;
}