【LeetCode题解】LeetCode 153. 寻找旋转排序数组中的最小值
【题目链接】
153. 寻找旋转排序数组中的最小值
【题目描述】
【题解】
以示例1为例,nums=[1,2,3,4,5]nums=[1,2,3,4,5]nums=[1,2,3,4,5],那么旋转后的数组一共有四种情况,分别是
nums0=[1,2,3,4,5]nums0=[1,2,3,4,5]nums0=[1,2,3,4,5],
nums1=[2,3,4,5,1]nums1=[2,3,4,5,1]nums1=[2,3,4,5,1],
nums2=[3,4,5,1,2]nums2=[3,4,5,1,2]nums2=[3,4,5,1,2],
nums3=[4,5,1,2,3]nums3=[4,5,1,2,3]nums3=[4,5,1,2,3],
nums4=[5,1,2,3,4]nums4=[5,1,2,3,4]nums4=[5,1,2,3,4]。
通过观察可以发现,numsnumsnums中的最小值为1。考虑数组中的最后一个元素nums[r]nums[r]nums[r],在最小值右侧的元素(不包括最后一个元素本身),它们的值一定都是严格小于nums[r]nums[r]nums[r];而在最小值左侧的元素,它们的值一定都严格大于nums[r]nums[r]nums[r]。因此,我们可以根据这一条性质,通过二分查找的方法找出最小值。
第一种情况:nums[mid]<nums[r]nums[mid]<nums[r]nums[mid]<nums[r]。
以nums=[5,1,2,3,4]nums=[5,1,2,3,4]nums=[5,1,2,3,4]为例,根据二分查找的思路,l=0,r=4,mid=2l=0,r=4,mid=2l=0,r=4,mid=2。nums[mid]=2<nums[r]=4nums[mid]=2<nums[r]=4nums[mid]=2<nums[r]=4,这说明nums[mid]nums[mid]nums[mid]是最小值右侧的元素,因此可以忽略二分查找区间的右边部分,所以r=mid=2r=mid=2r=mid=2。
第二步查找时,l=0,r=2,mid=1l=0,r=2,mid=1l=0,r=2,mid=1,nums[mid]=1<nums[r]=2nums[mid]=1<nums[r]=2nums[mid]=1<nums[r]=2,这说明nums[mid]nums[mid]nums[mid]是最小值右侧的元素,因此可以忽略二分查找区间的右边部分,所以r=mid=1r=mid=1r=mid=1。
第三步查找时,l=0,r=1,mid=0l=0,r=1,mid=0l=0,r=1,mid=0,nums[mid]=5>nums[r]=1nums[mid]=5>nums[r]=1nums[mid]=5>nums[r]=1,这说明nums[mid]nums[mid]nums[mid]是最小值左侧的元素,因此可以忽略二分查找区间的左边部分,所以l=mid+1=1l=mid+1=1l=mid+1=1。此时l=r=1l=r=1l=r=1,退出循环,nums[l]=1nums[l]=1nums[l]=1即为最小值。
第二种情况是:nums[mid]>nums[r]nums[mid]>nums[r]nums[mid]>nums[r]。
以nums=[2,3,4,5,1]nums=[2,3,4,5,1]nums=[2,3,4,5,1]为例,根据二分查找的思路,l=0,r=4,mid=2l=0,r=4,mid=2l=0,r=4,mid=2。nums[mid]=4>nums[r]=1nums[mid]=4>nums[r]=1nums[mid]=4>nums[r]=1,这说明nums[mid]nums[mid]nums[mid]是最小值左侧的元素,因此可以忽略二分查找区间的左边部分,所以l=mid+1=3l=mid+1=3l=mid+1=3。
第二步查找时,l=3,r=4,mid=3=3,r=4,mid=3=3,r=4,mid=3,nums[mid]=5>nums[r]=1nums[mid]=5>nums[r]=1nums[mid]=5>nums[r]=1,这说明nums[mid]nums[mid]nums[mid]是最小值左侧的元素,因此可以忽略二分查找区间的左边部分,所以l=mid+1=4l=mid+1=4l=mid+1=4。此时l=r=4l=r=4l=r=4,退出循环,nums[l]=1nums[l]=1nums[l]=1即为最小值。
由于数组不包含重复元素,并且只要当前的区间长度不为1,midmidmid就不会与rrr重合;而如果当前的区间长度为1,这说明我们已经可以结束二分查找了。因此不会存在nums[mid]=nums[r]nums[mid]=nums[r]nums[mid]=nums[r]的情况。
当二分查找结束时,我们就得到了最小值所在的位置。
【AC代码】
class Solution {
public:int findMin(vector<int>& nums) {int l = 0, r = nums.size() - 1;while(l < r) {int mid = l + r >> 1;if(nums[mid] < nums[r])r = mid;elsel = mid + 1;}return nums[l];}
};
【思考&收获】
传统的二分查找通常是通过midmidmid和targettargettarget的关系来确定查找范围,而这道题通过比较nums[mid]nums[mid]nums[mid]和nums[r]nums[r]nums[r]来判断最小值的位置,利用了数组旋转的特性。