简单版本:数组中的元素互不相同
LeetCode 153. Find Minimum in Rotated Sorted Array
领扣 153. 寻找旋转排序数组中的最小值
设置两个指针left = 0
和right = nums.size() - 1
每次循环一开始,判断nums[left] < nums[right]
是否成立,如果成立,那么说明数组nums[left..right]
的旋转值为0
,直接返回nums[left]
为最小元素
若数组旋转值不为0
,考察中间元素nums[mid]
情况1:nums[left] <= nums[mid]
(取等号是因为mid
有可能等于left
),此时可以排除掉从left
至mid
的元素,令left = mid + 1
情况2:nums[mid] < nums[right]
,此时可以排除掉从mid+1
至right
的元素,mid
元素本身不能排除,令right = mid
最终当left
等于right
时循环终止(我们希望最终剩下一个元素),指向最小的元素,故循环条件写为left < right
class Solution {
public:
int findMin(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
while( left < right ) // 我们希望最终剩下一个元素
{
if( nums[left] < nums[right] )
return nums[left];
int mid = left + ( right - left ) / 2;
if( nums[mid] >= nums[left] )
left = mid + 1;
else
right = mid;
}
return nums[left];
}
};
【相似题目】
Leetcode 278. First Bad Version
领扣 278. 第一个错误的版本
在数组[good, good, ..., good, bad, bad, ..., bad]
中寻找第一个bad
的位置
同样设置两个指针left = 0
和right = nums.size() - 1
,考察中间的mid
元素
情况1:mid
元素是good
,则可以排除从left
到mid
的元素,令left = mid + 1
情况2:mid
元素是bad
,则可以排除从mid + 1
到right
的元素,但mid
元素自身不能排除,故令right = mid
最终可以证明left
和right
会相等(也是因为我们希望剩下最后一个元素),指向第一个bad
,因此循环条件要写成left < right
简单的证明方法,举一个简单的例子[good, bad]
left = 1,right = 2,mid = 1
mid
元素是good
成立,left = mid + 1 = 2
最终left = right
,返回left = 1
// Forward declaration of isBadVersion API.
bool isBadVersion(int version);
class Solution {
public:
int firstBadVersion(int n) {
int left = 1, right = n;
while( left < right ) // 我们希望最终剩下一个元素
{
int mid = left + ( right - left ) / 2;
if( !isBadVersion(mid) )
left = mid + 1;
else
right = mid;
}
return left;
}
};
困难版本:数组中的元素有重复
LeetCode 154. Find Minimum in Rotated Sorted Array II
领扣 154. 寻找旋转排序数组中的最小值 II
采用和简单版本一样的思路,只不过对于nums[left]
、nums[mid]
和nums[right]
三者相等时,无法判断最小元素位于前半部还是后半部,此时将right
减1
即可(因为我们想找到第一个最小元素,而nums[right]
一定不会是我们想要的,故可以排除)
class Solution {
public:
int findMin(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
while( left < right ) // 我们希望最终剩下一个元素
{
if( nums[left] < nums[right] )
return nums[left];
int mid = left + ( right - left ) / 2;
// 如果三者相等,无法排除前半或后半的元素
if( nums[left] == nums[mid] && nums[mid] == nums[right] )
right--;
else if( nums[mid] >= nums[left] )
left = mid + 1;
else
right = mid;
}
return nums[left];
}
};