概述
- 局部有序数组内查找最小元素,数组内值互不相同
分析
- 要求 O ( l o g n ) O(logn) O(logn),说明还是需要二分法,并且局部有序也是支持二分操作的
思路
-
Q1:如何确定下一个查找区间?
我们每次得到的值是
num[mid]
,我们想要查找的值是min
。由左图可知,当mid在1处时,应该查找右区间;当mid在2处时,应该查找左边区间 -
Q2:如何确定mid的位置?
通过分析,
num[mid]
可以和num[l]
或num[r]
比较- 如果和
num[l]
比较,num[mid]
>时选择右区间;<时选择左区间 - 如果和
num[r]
比较,num[mid]
>时选择右区间;<时选择左区间 - 但是注意特殊情况,也就是右图,我们知道
num[mid]<num[r]
时,左区间;num[mid]>num[l]
时选择左区间
所以为了一致性,选择和
num[r]
相比 - 如果和
-
Q3:什么时候找到答案?
因为我们的区间总是根据min值移动,所以当不用再移动区间时,就说明找到了min
即,l==r时
实现代码
class Solution {
public:
int findMin(vector<int>& nums) {
int l = 0, r = nums.size() - 1;
while ( l < r) {
int mid = (l + r) / 2;
if (nums[mid] < nums[r]) // 这里注意选择和num[r]比较而不是num[0]
r = mid; // 最小值有可能就是nums[mid]
else
l = mid + 1;
}
// 当 l == r的时候,就说明找到最小值了
return nums[l];
}
};
拓展
和33.搜索旋转排序数组的不同之处
-
此题的targe相当于一个未知的最小值,所以不需要和nums[mid]比较大小,可以根据mid位置直接确定下一个区间
-
33题的target是确定的,就算知道了mid的位置,还需要比较target和nums[mid]的大小,才能确定下一个区间
-
在mid的某些情况下,target是可能出现在两个区间的
就那上面的左图分析,如果mid在2处,target>nums[mid],target是可能出现在mid的左右两个区间的
所以和左端 or 右端比较都可以,因为根据mid位置是无法直接确定下个区间的
-
和154. 寻找旋转排序数组中的最小值 II的不同之处
- 154题中,数组内可能有重复的数值,那么
num[r]==num[mid]
时,是无法确定mid执行的是1处还是2处 - 但是可以将r-1,因为如果num[r]是最小值,那么num[mid]也是最小值,不会影结果