4.21数组旋转找最小值 - WisperDin/blog GitHub Wiki
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
在数组旋转后,一个数组被划分成了两个有序部分,应利用好这个特性来解决问题
注意数组中可能会有重复的元素(非递减序列)
-
暴力遍历找最小元素,时间复杂度O(n)
-
稍微优化的遍历,从起始位置遍历,直至发现后一个元素比前一个元素要小,该元素就是最小元素,如一直没发现有这种情况,则取第一个元素。复杂度取决于旋转的元素个数
-
二分查找,同样先处理没旋转的情况,之后
考虑到数组两部分都是有序的,假设旋转到后面的数组部分为A,剩下的部分为B,数组构成[B,A] B中任意一个元素>=A中任意一个元素
- 若start<=mid [start,end] 则这部分必定为非递减的,区间内仅存在B的元素(B的元素不一定全存在在这个区间)所以 start > mid 时, A,B元素的交界处必定在此处
- 若mid <= end [mid,end] 类似地,区间内仅存在A的元素,所以 mid > end 时 ,A,B 元素交界处必定在此处
- 现在考虑除 (start >mid || mid >end) 的情况 即 (start <= mid <= end) ,此情况其实就是未旋转的情况,已经在一开始排除掉,而且在二分查找中每次的进入A,B交界处的区间,也不会出现这种情况
- 最终情况: 注意当最后二分查找区间缩小至只有两个元素时,此时找到的就是A,B组的交界处,直接取end位置的元素返回即可
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
if (rotateArray.size()==0)
return 0 ;
int start = 0;
int end = rotateArray.size()-1;
int mid;
//直接处理没有旋转的情况
if (rotateArray[0]<rotateArray[end])
return rotateArray[0];
while (true){
if (start+1==end)
return rotateArray[start]>rotateArray[end]?rotateArray[end]:rotateArray[start];
mid = (start+end)/2;
//选 (前大于后) start>mid || mid > end 的部分继续二分
if (rotateArray[start]>rotateArray[mid]){
end = mid;
continue;
}
if (rotateArray[mid] > rotateArray[end]){
start = mid;
continue;
}
//不可能出现的情况
return rotateArray[end];
}
}
};
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
if(rotateArray.size()==0)
return 0;
int firstEle = rotateArray[0];
int i,cursor;
for (i = 1,cursor = 0 ; i<rotateArray.size();i++,cursor++){
if(rotateArray[i]<rotateArray[cursor])
break;
}
return i==rotateArray.size()?firstEle:rotateArray[i];
}
};