旋转数组的最小数字
参见《剑指Offer》P66
题目描述:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思路:
根据题意,将一个数组旋转之后,变成了两个独立的非降序的数组,且前一个数组的元素应该大于后一个数组的元素。我们要找的最小的数字就位于两个数组交叉处,也就是第二个数组的首元素。
利用二分查找思想,查找范围为数组的[left,right],开始left=0,right=length-1,中间位置mid=(left+right)/2。
如果中间元素大于left位置的元素,说明中间元素位于前一个递增数组中,此时可以将left移动到mid;
如果中间元素小于right位置的元素,说明中间元素位于后一个递增数组中,此时可以将right移动到mid;
如此循环下去,直到right-left=1,此时right就是我们要找的元素。
特殊情况:如10111和11101都是01111的旋转,此时left==mid==right,此时无法判断中间元素是位于前边的递增数组还是位于后边的递增数组,只能在left到right之间顺序查找。
代码如下:
#include<iostream>
#include<vector>
#include<algorithm>
#include<limits.h>
using namespace std;
//顺序搜索
int orderedSearch(vector<int> rotateArray,int lo,int hi) {
int result = INT_MAX;
for(int i=lo;i<=hi;i++) {
result = rotateArray[i]<result? rotateArray[i]:result;
}
return result;
}
int minNumberInRotateArray(vector<int> rotateArray) {
if(rotateArray.size()==0) return 0;
if(rotateArray.size()==1) return rotateArray[0];
int left = 0,right = rotateArray.size()-1;
int mid = left; //数组原来有序,直接返回
while(rotateArray[left]>=rotateArray[right]) {
if(right-left == 1) {
mid = right;
break;
}
mid = (left+right)/2;
if(rotateArray[mid]>=rotateArray[left])
left = mid;
else if(rotateArray[mid]<=rotateArray[right])
right = mid;
else if(rotateArray[mid] == rotateArray[left] == rotateArray[right])
return orderedSearch(rotateArray, left, right);
}
return rotateArray[right];
}
int main()
{
vector<int> a = {1,1,1,0,1};
cout<<minNumberInRotateArray(a)<<endl;
return 0;
}