题目描述:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思路:旋转之后的数组可划分为前后两个有序子数组,且前面数组元素必定比后面数组元素大,现在定义两个指针,left指向前段数组,right指向后段数组,mid=left+(right-left)/2,mid始终指向left和right中间的元素,如下情况:若mid元素比left元素大,则说明mid扔处在前面的数组中,令left=mid ; 若mid比left小,则说明mid处在后面数组中(因为left是从left到right这段里前面大数组最小的元素),令right=mid;若无法分清mid处在前面还是后面,则说明数组中有重复元素,只能便利来寻找最小值了。以上思路在无重复元素时时间复杂度为O(logn)
代码实现:
int MinOrder(vector<int> Array,int left,int right)
{
int min=left;
for(int i=left;i<=right;i++)
{
if(Array[i]<Array[min])
{
min=i;
}
}
return Array[min];
}
int minNumberInRotateArray(vector<int> rotateArray) {
if(rotateArray.empty())
return 0;
int left=0;//left始终指向前面数组
int right=rotateArray.size()-1;//right始终指向后面数组
int mid;//left和right中间元素的下标
while(rotateArray[left]>=rotateArray[right])
{
if(left+1==right)//到达前后两个子数组的边界
{
//找到最小值下表为right
mid=right;
break;
}
mid=left+(right-left)/2;
if(rotateArray[mid]==rotateArray[right]&&rotateArray[mid]==rotateArray[left])
{
//有重复值时会出现此情况
//一旦发现无法确定mid所在值是属于前面数组还是后面数组,则遍历从left到right的这段序列,最小值必定是在这之间中间
return MinOrder(rotateArray,left,right);
}
if(rotateArray[mid]>=rotateArray[left])
{
//此时mid所在元素一定是在后面子数组
left=mid;//right前移
}
else right=mid; //此时mid所在元素一定是在后面子数组,left后移
}
return rotateArray[mid];
}