题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减序列的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
解题思路
- 简单直接粗暴方法:从头至尾遍历数组,找出最小元素,时间复杂度O(n).
- 排序数组中可以用二分查找法(时间复杂度O(log n)),此旋转数组基本有序。
- 用left和right指向数组第一个和最后一个元素。按旋转数组规则,第一个元素应该大于或者等于最后一个元素。找到中间元素middle。若middle元素大于等于left元素,前半部分递增,最小元素在后半部分,将left移至middle位置;若middle元素小于等于right元素,后半部分递增,最小元素在前半部分,将right移至middle位置。 这样就能缩小一半的范围,然后重新做新一轮查找。
- 最后left指向前面子数组的最后一个元素,right指向后面子数组的第一个元素,两者相邻,right所指元素为最小元素,循环结束。
- 特殊情形一,原数组的旋转了0个或n个元素,旋转数组与原数组相同,此时最小元素在最前面。
- 特殊情形二,当left,right和middle均相同时,无法判断middle元素位于前半部分还是后半部分。如原数组{0,1,1,1,1,1},其旋转数组{1,0,1,1,1,1}和{1,1,1,1,0,1}无法判断。此时需要暴力顺序查找。
参考代码
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
if ( rotateArray.empty() ) {
//throw new std::exception("Invalid parameters!");
return 0;
}
int left = 0;
int right = rotateArray.size()-1;
int middle = left;//应对特殊情形一,left所指小于right所指,跳过while循环。
while (rotateArray[left] >= rotateArray[right] ) {
if ( right - left == 1 ) {
middle = right;
break;
}
middle = (right+left)/2;
if ( rotateArray[middle] == rotateArray[left] //特殊情形二
&& rotateArray[middle] == rotateArray[right] ) {
return minNumberInOrderArray(rotateArray, left, right);
}
if ( rotateArray[middle] >= rotateArray[left] ) {
left = middle;
} else if ( rotateArray[middle] <= rotateArray[right] ) {
right = middle;
}
}
return rotateArray[middle];
}
//顺序查找
int minNumberInOrderArray(vector<int> rotateArray, int left, int right) {
int minNumber = rotateArray[left];
for ( int i = left+1; i <= right; i++ ) {
if ( minNumber > rotateArray[i] ) {
minNumber = rotateArray[i];
}
}
return minNumber;
}
};