思路
题目强调了是一个有序(升序)的数组,且提示中说明元素不重复,这样就满足了使用二分法的条件,我们只需要处理好边界就好。
在全闭区间[left,right]的代码
class Solution {
public:
int search(vector<int>& nums, int target) {
//1.确定要寻找元素的闭区间[left,right]
int left = 0;
int right = nums.size()-1;
//2.在[left,right]的闭区间寻找元素
while(left<=right)
{
int mid = (left+right)/2;//注意mid写在循环内,每次循环开始更新mid
if(target>nums[mid])//下面有解析
{
left=mid+1;
}
else if(target<nums[mid])
{
right = mid-1;
}
else
{
return mid;//target与nums[mid]相等返回下标
}
}
//3.找不到返回-1
return -1;
}
};
解析
以下图为例
target=9时,nums[mid]<target ,故下一次的查找区间为[mid+1,right],即[4, 6]。
同理,若target=0时,nums[mid]>target,下一次的查找区间为1[left,mid-1],即[0, 2]。
target=5时,直接返回mid,下标对应3
所以若target=6不再数组中,我们只需要在循环结束后返回-1,说明找不到。
循环结束标志
这里在left<=right的时候进入循环,当right>left时,left与right间没有元素,自然要出循环。
至于为什么有=,我们以单元素数组[1]为例,此时left=mid=right=0,无论target等于几,我们仍需要再数组[1]中查找一番,所以需要=。
若有开区间怎么处理
上面我们给出了全闭区间[left,right]处理的解析,如果要处理的是[left,right)呢?
首先我们可以想到的是将问题转化为处理[left,right-1),再复用上面的思想。
那如果要单独处理呢?
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size()-1;
while(left<right)
{
//这里left=right没有进入循环的意义了
int mid = (left+right)/2;
if(target>nums[mid])
{
left=mid+1;//更改搜索区间为[mid+1,right]
}
else if(target<nums[mid])
{
right = mid;//更改搜索区间为[left,mid)
}
else
{
return mid;
}
}
return -1;
}
};
解析
我们仍然以此图为例:
对于target=9而言,nums[mid]<target,查找的区间为从[left,right)变为[mid+1,right),即left=mid+1。
对于target=0而言,nums[mid]>target,查找的区间从[left,right)变为[left,mid],即right=mid。
循环结束标志
为什么是left<right,没有了=呢,以单元素数组[1]为例,此时left=mid=right=0,我们要查找的区间变成了[0,0),我们认为这样没有意义。