【LeetCode题解】LeetCode 153. 寻找旋转排序数组中的最小值 - 实践
【题目链接】
153. 寻找旋转排序数组中的最小值
【题目描述】

【题解】
以示例1为例,n
u
m
s
=
[
1
,
2
,
3
,
4
,
5
]
nums=[1,2,3,4,5]nums=[1,2,3,4,5],那么旋转后的数组一共有四种情况,分别是
n
u
m
s
0
=
[
1
,
2
,
3
,
4
,
5
]
nums0=[1,2,3,4,5]nums0=[1,2,3,4,5],
n
u
m
s
1
=
[
2
,
3
,
4
,
5
,
1
]
nums1=[2,3,4,5,1]nums1=[2,3,4,5,1],
n
u
m
s
2
=
[
3
,
4
,
5
,
1
,
2
]
nums2=[3,4,5,1,2]nums2=[3,4,5,1,2],
n
u
m
s
3
=
[
4
,
5
,
1
,
2
,
3
]
nums3=[4,5,1,2,3]nums3=[4,5,1,2,3],
n
u
m
s
4
=
[
5
,
1
,
2
,
3
,
4
]
nums4=[5,1,2,3,4]nums4=[5,1,2,3,4]。
通过观察可以发现,n
u
m
s
numsnums中的最小值为1。考虑数组中的最后一个元素n
u
m
s
[
r
]
nums[r]nums[r],在最小值右侧的元素(不包括最后一个元素本身),它们的值一定都是严格小于n
u
m
s
[
r
]
nums[r]nums[r];而在最小值左侧的元素,它们的值一定都严格大于n
u
m
s
[
r
]
nums[r]nums[r]。因此,我们可以根据这一条性质,通过二分查找的方法找出最小值。
第一种情况:n
u
m
s
[
m
i
d
]
<
n
u
m
s
[
r
]
nums[mid]<nums[r]nums[mid]<nums[r]。
以n
u
m
s
=
[
5
,
1
,
2
,
3
,
4
]
nums=[5,1,2,3,4]nums=[5,1,2,3,4]为例,根据二分查找的思路,l
=
0
,
r
=
4
,
m
i
d
=
2
l=0,r=4,mid=2l=0,r=4,mid=2。n
u
m
s
[
m
i
d
]
=
2
<
n
u
m
s
[
r
]
=
4
nums[mid]=2<nums[r]=4nums[mid]=2<nums[r]=4,这说明n
u
m
s
[
m
i
d
]
nums[mid]nums[mid]是最小值右侧的元素,因此可以忽略二分查找区间的右边部分,因此r
=
m
i
d
=
2
r=mid=2r=mid=2。
第二步查找时,l
=
0
,
r
=
2
,
m
i
d
=
1
l=0,r=2,mid=1l=0,r=2,mid=1,n
u
m
s
[
m
i
d
]
=
1
<
n
u
m
s
[
r
]
=
2
nums[mid]=1<nums[r]=2nums[mid]=1<nums[r]=2,这说明n
u
m
s
[
m
i
d
]
nums[mid]nums[mid]是最小值右侧的元素,因此可以忽略二分查找区间的右边部分,所以r
=
m
i
d
=
1
r=mid=1r=mid=1。
第三步查找时,l
=
0
,
r
=
1
,
m
i
d
=
0
l=0,r=1,mid=0l=0,r=1,mid=0,n
u
m
s
[
m
i
d
]
=
5
>
n
u
m
s
[
r
]
=
1
nums[mid]=5>nums[r]=1nums[mid]=5>nums[r]=1,这说明n
u
m
s
[
m
i
d
]
nums[mid]nums[mid]是最小值左侧的元素,因此能够忽略二分查找区间的左边部分,所以l
=
m
i
d
+
1
=
1
l=mid+1=1l=mid+1=1。此时l
=
r
=
1
l=r=1l=r=1,退出循环,n
u
m
s
[
l
]
=
1
nums[l]=1nums[l]=1即为最小值。
第二种情况是:n
u
m
s
[
m
i
d
]
>
n
u
m
s
[
r
]
nums[mid]>nums[r]nums[mid]>nums[r]。
以n
u
m
s
=
[
2
,
3
,
4
,
5
,
1
]
nums=[2,3,4,5,1]nums=[2,3,4,5,1]为例,根据二分查找的思路,l
=
0
,
r
=
4
,
m
i
d
=
2
l=0,r=4,mid=2l=0,r=4,mid=2。n
u
m
s
[
m
i
d
]
=
4
>
n
u
m
s
[
r
]
=
1
nums[mid]=4>nums[r]=1nums[mid]=4>nums[r]=1,这说明n
u
m
s
[
m
i
d
]
nums[mid]nums[mid]是最小值左侧的元素,因此可以忽略二分查找区间的左边部分,所以l
=
m
i
d
+
1
=
3
l=mid+1=3l=mid+1=3。
第二步查找时,l=
3
,
r
=
4
,
m
i
d
=
3
=3,r=4,mid=3=3,r=4,mid=3,n
u
m
s
[
m
i
d
]
=
5
>
n
u
m
s
[
r
]
=
1
nums[mid]=5>nums[r]=1nums[mid]=5>nums[r]=1,这说明n
u
m
s
[
m
i
d
]
nums[mid]nums[mid]是最小值左侧的元素,因此能够忽略二分查找区间的左边部分,所以l
=
m
i
d
+
1
=
4
l=mid+1=4l=mid+1=4。此时l
=
r
=
4
l=r=4l=r=4,退出循环,n
u
m
s
[
l
]
=
1
nums[l]=1nums[l]=1即为最小值。
由于数组不包括重复元素,并且只要当前的区间长度不为1,m
i
d
midmid就不会与r
rr重合;而如果当前的区间长度为1,这说明大家已经可以结束二分查找了。因此不会存在n
u
m
s
[
m
i
d
]
=
n
u
m
s
[
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;
else
l = mid + 1;
}
return nums[l];
}
};
【思考&收获】
传统的二分查找通常是通过m
i
d
midmid和t
a
r
g
e
t
targettarget的关系来确定查找范围,而这道题通过比较n
u
m
s
[
m
i
d
]
nums[mid]nums[mid]和n
u
m
s
[
r
]
nums[r]nums[r]来判断最小值的位置,利用了数组旋转的特性。

浙公网安备 33010602011771号