最近做题遇到二分查找,对于区间的取值以及最后的结果模棱两可。对于(l<=r)这种闭区间的。取值的范围是[left,right],一定要保证每次循环结束后left+1或者right-1,结束的状态left>right,left在右边,right在左边,目标值下标确定是left。
278. 第一个错误的版本
本题相当于一个数组,左边都是false,某一个位置开始都是true。需要找到第一个出现的true。使用闭区间计算,最后的时候left>right,所以left就是第一个出现的true,right是最后一个false,直接返回left即可。
/* The isBadVersion API is defined in the parent class VersionControl.
boolean isBadVersion(int version); */
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
int l=1;
int r=n;
while(l<=r){
int mid=l+(r-l)/2;
if(isBadVersion(mid))
r=mid-1;
else
l=mid+1;
}
return l;
}
}
剑指 Offer 53 - II. 0~n-1中缺失的数字
与上题分析相同,左边都是满足+1递增的,找到第一个不满足的,也就是返回右边部分的第一个,直接返回left就可以
class Solution {
public int missingNumber(int[] nums) {
int j=nums.length-1;
int i=0;
while(i<=j){
int mid=i+(j-i)/2;
if(mid==nums[mid])
i=mid+1;
else
j=mid-1;
}
return i;
}
}
69. x 的平方根
左边的数都是满足mid* mid<=x,右边从某个位置开始mid*mid>x,所以需要找到左边的最后一个数,实际上就是返回right的下标,但本题考虑int溢出问题,所以使用ans记录左边的最后一个下标,来代替返回high的位置。
class Solution {
public int mySqrt(int x) {
if(x==1)
return 1;
int low=0;
int high=x;
int mid=0;
int ans=0;//记录最后一个满足的下标
while(low<=high){
mid=low+((high-low)>>1);
if((long)mid*mid<=x){
ans=mid;
low=mid+1;//low最后是不满足题意的,ans是最后一个满足的
}
else
high=mid-1;
}
return ans;
}
}
35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。左边的判断条件是(nums[mid]<target),所以left最后是大于等于目标值的第一个。而right是小于目标值的最后一个。返回left即可。
class Solution {
public int searchInsert(int[] nums, int target) {
int n=nums.length;
if(n==0||target<nums[0])
return 0;
int l=0;
int r=n-1;
while(l<=r){
int mid=(r-l)/2+l;
if(nums[mid]>=target){
r=mid-1;
}
if(nums[mid]<target)
l=mid+1;
}
return l;
}
}