问题描述
已知一个长度为 n
的数组,预先按照升序排列,经由 1
到 n
次 旋转 后,得到输入数组。例如,原数组 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
,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
你必须设计一个时间复杂度为 O(log n)
的算法解决此问题。
示例 1:
输入:nums = [3,4,5,1,2] 输出:1 解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。
示例 2:
输入:nums = [4,5,6,7,0,1,2] 输出:0 解释:原数组为 [0,1,2,4,5,6,7] ,旋转 3 次得到输入数组。
示例 3:
输入:nums = [11,13,15,17] 输出:11 解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。
提示:
n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
nums
中的所有整数 互不相同nums
原来是一个升序排序的数组,并进行了1
至n
次旋转
解决思路
class Solution {
public:
int findMin(vector<int>& nums) {
int i = 0, j = nums.size() - 1;
while (i < j) {
int mid = (i + j) >> 1;
if (nums[mid] < nums[j]) {
j = mid;
} else {
i = mid + 1;
}
}
return nums[i];
}
};
这段代码是一个用于查找旋转排序数组中的最小元素的 C++ 函数。旋转排序数组指的是数组在某个枢纽点进行了旋转。例如,原数组为 [1,2,3,4,5],旋转后可能变为 [3,4,5,1,2]。这段代码的目标是找出这种数组中的最小元素。
这里是详细的解析:
-
初始化索引:
int i = 0, j = nums.size() - 1;
i
和j
分别初始化为数组的起始位置和结束位置的索引。
-
循环条件:
while (i < j)
- 只要
i
小于j
,循环继续执行。目的是缩小查找范围直到找到最小值。
- 只要
-
计算中点:
int mid = (i + j) >> 1;
- 使用位运算
>>
来快速求得i
和j
的平均值,即中点mid
,这是一个常用的优化技巧。
- 使用位运算
-
判断和移动索引:
if (nums[mid] < nums[j])
- 如果中间位置的元素小于最右边的元素,说明最小值在左半部分,包括中点。因此,将
j
移动到mid
。
- 如果中间位置的元素小于最右边的元素,说明最小值在左半部分,包括中点。因此,将
else
- 如果不满足上述条件,则最小值在右半部分,但不包括中点。因此,将
i
移动到mid + 1
。
- 如果不满足上述条件,则最小值在右半部分,但不包括中点。因此,将
-
返回最小值:
return nums[i];
- 循环结束后,
i
将指向最小元素的位置。
- 循环结束后,
总之,这段代码利用二分查找算法的原理,在部分排序的数组中高效地查找最小元素。通过每次比较中点和末尾点的值,来决定搜索范围的缩减方向。这种方法的时间复杂度是 O(log n),非常适合处理大数据集。