当你的才华还撑不起你的野心时,你应该静下心去学习 。 |
---|
题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。本题是练习二分法的一道经典例题,也是一道常见面试题。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
示例
输入:[3,4,5,1,2]
返回值:1
解题思路
- 初始化: 声明 i, j 双指针分别指向 numsnums 数组左右两端;
- 循环二分: 设 m = (i + j) / 2 为每次二分的中点( “/” 代表向下取整除法,因此恒有 i≤m<j ),可分为以下三种情况:
- 当 nums[m] > nums[j] 时: m 一定在 左排序数组 中,即旋转点 x 一定在 [m + 1, j] 闭区间内,因此执行 i = m + 1;
- 当 nums[m] < nums[j] 时: m 一定在 右排序数组 中,即旋转点 x 一定在[i, m] 闭区间内,因此执行 j = m;
- 当 nums[m] = nums[j] 时: 无法判断 m 在哪个排序数组中,即无法判断旋转点 x 在 [i,m] 还是 [m+1,j] 区间中。解决方案: 执行 j = j - 1j=j−1 缩小判断范围,
- 返回值: 当 i = ji=j 时跳出二分循环,并返回 旋转点的值 nums[i] 即可。
寻找旋转数组的最小元素即为寻找 右排序数组 的首个元素 nums[x] ,称 x 为 旋转点 。
时间复杂度 O(logN) : 在特例情况下(例如[1,1,1,1]),会退化到 O(N)。
空间复杂度 O(1) : i , j , m 变量使用常数大小的额外空间。
参考代码
Java版本
class Solution {
public:
int minArray(vector<int>& numbers) {
int i = 0, j = numbers.size() - 1;
while (i < j) {
int m = (i + j) / 2;
if (numbers[m] > numbers[j]) i = m + 1;
else if (numbers[m] < numbers[j]) j = m;
else j--;
}
return numbers[i];
}
};
CPP版本
class Solution {
public:
int minArray(vector<int>& numbers) {
int i = 0, j = numbers.size() - 1;
while (i < j) {
int m = (i + j) / 2;
if (numbers[m] > numbers[j]) i = m + 1;
else if (numbers[m] < numbers[j]) j = m;
else j--;
}
return numbers[i];
}
}
创作不易,你的鼓励是我创作的动力,如果你有收获,点个赞吧👍 |
---|