二分查找原理是并不难的,就是从一个有序数组中找到想要的target,但是对于边界问题是比较难把握的,下面就分享一下:
(1)左闭右闭区间
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0;
int right=nums.size()-1;
while(left<=right)
{
int middle=(left+right)/2;
if(nums[middle]>target)
{
right=middle-1;
}
else if(nums[middle]<target)
{
left=middle+1;
}
else{
return middle;
}
}
return -1;
}
};
为什么这个称为左闭右闭区间呢,因为算法中left是从0开始取的,而右边界right是从n(数组长度)-1开始取,都是能取到的,所以是左闭右闭区间,首先循环进行的条件到底是“<”还是“<=”,打个比方,[0,0]这个区间是不是合法的呢,当然是,因为区间里只有一个数字0,那么left能不能等于right呢,答案是yes,所以结束条件是left>rigth时循环结束。
我们找到middle之后,如果nums[middle]是大于target的,证明我们的target在左区间内,因此要移动right,此时到底是取middle-1还是取middle呢,答案是middle-1,因为我们在判断的时候已经判断了此时的nums[middle]是大于target的,那middle下标对应的值就不需要再被拿来查找了,所以是middle-1.同理,当nums[middle]<target时,需要移动left,也是同理,应该取middle+1
(2)左闭右开区间
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0,right=nums.size();
while(left<right)
{
int middle=(left+right)/2;
if(nums[middle]<target)
{
left=middle+1;
}
else if(nums[middle]>target)
{
right=middle;
}
else
{
return middle;
}
}
return -1;
}
};
这次和上面的区别是右边界right取到了nums.size(),但实际数组下标是没有的,所以右边是开区间,那我们循环进行的条件是什么呢,同理[0,0)是不是合法区间呢,当然不是,所以条件就是left<right。
那么当nums[middle]>target时,要移动左区间left的值,是取middle还是middle+1呢,我们已经判断了middle位置对应的值是不满足条件的,那么肯定是取middle+1处的值,因为左区间是闭区间,是可以取到的;当nums[middle]<target时,要移动右区间right的值,该取什么呢,仔细想想,当前middle位置的值显然已经不满足,但是右区间是开区间,middle处的值是取不到的,所以只需要让right=middle就可以,这就解决了边界问题,希望对大家能有帮助。