LC 153. 寻找旋转排序数组中的最小值

题目描述

这是 LeetCode 上的 153. 寻找旋转排序数组中的最小值 ,难度为 中等

已知一个长度为 n 的数组,预先按照升序排列,经由 1n 次 旋转 后,得到输入数组。

例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:

  • 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
  • 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]

注意,数组 $[a[0], a[1], a[2], …, a[n-1]]$ 旋转一次 的结果为数组 $[a[n-1], a[0], a[1], a[2], …, a[n-2]]$。

给你一个元素值 互不相同 的数组 nums,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。

请你找出并返回数组中的最小元素。

示例 1:

1
2
3
4
5
输入:nums = [3,4,5,1,2]

输出:1

解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。

示例 2:
1
2
3
4
5
输入:nums = [4,5,6,7,0,1,2]

输出:0

解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。

示例 3:
1
2
3
4
5
输入:nums = [11,13,15,17]

输出:11

解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。

提示:

  • $n = nums.length$
  • $1 <= n <= 5000$
  • $-5000 <= nums[i] <= 5000$
  • nums 中的所有整数互不相同
  • nums 原来是一个升序排序的数组,并进行了 1n 次旋转

二分查找

今天这道题和昨天的 81. 搜索旋转排序数组 II 相比,有了限制条件「所有整数互不相同」。

因此我们不需要进行「恢复二段性」的预处理,是可以做到严格 $O(\log{n})$ 的复杂度。

我们仍然从「二分」的本质「二段性」进行出发分析:

经过旋转的数组,显然前半段满足 >= nums[0],而后半段不满足 >= nums[0]。我们可以以此作为依据,通过「二分」找到旋转点。然后通过旋转点找到全局最小值即可。

Java 代码:

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public int findMin(int[] nums) {
int n = nums.length;
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if (nums[mid] >= nums[0]) l = mid;
else r = mid - 1;
}
return r + 1 < n ? nums[r + 1] : nums[0];
}
}

C++ 代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
int findMin(vector<int>& nums) {
int n = nums.size();
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if (nums[mid] >= nums[0]) l = mid;
else r = mid - 1;
}
return r + 1 < n ? nums[r + 1] : nums[0];
}
};

Python 代码:
1
2
3
4
5
6
7
8
9
class Solution:
def findMin(self, nums: List[int]) -> int:
n = len(nums)
l, r = 0, n - 1
while l < r:
mid = l + r + 1 >> 1
if nums[mid] >= nums[0]: l = mid
else: r = mid - 1
return nums[r + 1] if r + 1 < n else nums[0]

TypeScript 代码:
1
2
3
4
5
6
7
8
9
10
function findMin(nums: number[]): number {
const n: number = nums.length;
let l: number = 0, r: number = n - 1;
while (l < r) {
const mid: number = l + r + 1 >> 1;
if (nums[mid] >= nums[0]) l = mid;
else r = mid - 1;
}
return r + 1 < n ? nums[r + 1] : nums[0];
};

  • 时间复杂度:$O(\log{n})$
  • 空间复杂度:$O(1)$

其他「二分」相关题解


最后

这是我们「刷穿 LeetCode」系列文章的第 No.153 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。

在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。

为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode

在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。