题目:把一个数组最开始的若干元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小的元素。
例如:数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1.
本题目是直接给的旋转的数组:那么数组如何旋转呢?其实也很简单:
首先确保给数组排序,最好的时间复杂度O(NLogN)。
(1)如果元素的个数是奇数:最中间的元素不动,i和j都指向中间元素的下标。然后i++和j--,同时交换;停止的条件是i<0;
(2)如果元素的个数是偶数:i=n/2-1;j=n/2;i--;j++;停止的条件是i<0;
然后回到正题,求翻转数组的最小数字:
方案一:循环遍历法。此法比较笨,一般这样的方法就不要说了,一般的都能想到。时间复杂度是O(N)。
方案二:二分查找法。
以上面的题目为例:{3,4,5,1,2};
交换以后,被切成两个递增的序列。我们可以发现第一个元素是大于或等于第二个元素的(当然还有特例:如果把前面的0个元素搬到后面,第一元素小于最后的一个元素)。
(1)移动了0个元素,也就是还是原先的序列;
例如:数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1.
本题目是直接给的旋转的数组:那么数组如何旋转呢?其实也很简单:
首先确保给数组排序,最好的时间复杂度O(NLogN)。
(1)如果元素的个数是奇数:最中间的元素不动,i和j都指向中间元素的下标。然后i++和j--,同时交换;停止的条件是i<0;
(2)如果元素的个数是偶数:i=n/2-1;j=n/2;i--;j++;停止的条件是i<0;
然后回到正题,求翻转数组的最小数字:
方案一:循环遍历法。此法比较笨,一般这样的方法就不要说了,一般的都能想到。时间复杂度是O(N)。
方案二:二分查找法。
以上面的题目为例:{3,4,5,1,2};
交换以后,被切成两个递增的序列。我们可以发现第一个元素是大于或等于第二个元素的(当然还有特例:如果把前面的0个元素搬到后面,第一元素小于最后的一个元素)。
先看常规的方法:采用二分查找,不断的缩小范围,当最大和最小相邻的时候停止。具体示意如下图一:
图一
注意两种特殊情况:(1)移动了0个元素,也就是还是原先的序列;
(2)对于如下数组,当第一个指针和第二个指针以及中间元素都相等时,我们无法判断增减序列,进而进行缩小范围。此时我们必须采用顺序查找;
第二种情况如下图二:
图二
具体代码实现如下:
#include<iostream>
using namespace std;
int FindOrder(int *array,int length);
int FindMin(int *array,int length);
int arr1[5]={3,4,5,1,2};
int arr2[5]={1,0,1,1,1};
int FindMin(int *array,int length)
{
if(NULL==array || length <=0)
throw "INVALID INPUT!";
int index1=0;
int index2=length-1;
int MidInde=index1;//十分必要,因为这个事避免上述说的注意1时的特殊情况;
while(array[index1]>=array[index2])
{
if(1==index2-index1)
return array[index2];
MidInde=(index1+index2)/2;
if(array[index1]==array[index2] && array[index2]==array[MidInde])//特殊情况(2);
return FindOrder(array,length);//顺序查找;
if(array[MidInde]>=array[index1])
index1=MidInde;
if(array[MidInde]<=array[index2])
index2=MidInde;
}
return array[index1];
}
int FindOrder(int *array,int length)
{
int min=array[0];
for(int i=0;i<length;i++)
{
if(min>array[i])
{
min=array[i];
}
}
return min;
}
int main()
{
cout<<"In arr1,the min is :"<<FindMin(arr1,5)<<endl;
cout<<"In arr2,the min is :"<<FindMin(arr2,5)<<endl;
system("pause");
return 0;
}
运行结果: