输出一个为递增排序数组的旋转数组中的最小元素——8
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为数组{1, 2,3, 4, 5}的一个旋转,该数组的最小值为1。
当然了,将数组遍历一遍肯定能找出最小值,但其时间复杂度为O(N),效率是最低的,因此,应该有一种更高效的解决办法。
因为原数组是递增的,因此数组的第一个元素一定是最小值,而旋转之后,其最小值就会成为旋转的分界点,因此,查找一个旋转之后数组的最小值可以变成查找一个旋转数组的旋转点。而我们仍然可以发现,在旋转点之前的序列是递增有序的,而在旋转点之后的序列也是递增有序的,因此可以这样判断:
取数组的中间值;
如果中间值比最左值大且比最右值小,那么这个数组就是递增数组旋转幅度为0,最小值就为数组第一个值,直接返回;
如果中间值比左边一个数小且比右边一个数小,那么中间值就为旋转点也就是最小值,直接返回;
如果中间值比最左值大且比最右值大,那么中间值往左一定是递增有序的,而旋转点一定在中间值往右,将范围缩到中间值右半边重新从第1步开始;
如果中间值比最左值小且比最右值小,那么中间值往右一定是递增有序的,而旋转点一定在中间值往左,将范围缩到中间值左半边重新从第1步开始;
上面的分析其实是相当于在用二分查找来做,这样就将时间复杂度降为了O(lgN),下面用代码来实现:
#include<iostream>#include<assert.h>usingnamespacestd;intfind_min_num(constint*arr,size_tn){assert(arr&&n);intleft=0;intright=n-1;intmid=(right-left)/2;while(left<right){if((arr[left]<=arr[mid])&&(arr[mid]<=arr[right])){break;//当数组区间为递增时,最小值就为最左值}elseif((arr[mid-1]>arr[mid])&&(arr[mid+1]>arr[mid])){returnarr[mid];//当取到的中间值就为旋转点时,最小值就为中间值}elseif((arr[left]<=arr[mid])&&(arr[mid]>=arr[right])){left=mid+1;//当中间值比左边大且比右边大时}else{right=mid-1;//除去上面的三种情况就只剩一种了,那就是中间值比左线小且比右边小}mid=(right-left)/2+left;}returnarr[left];}intmain(){intarr[]={8,9,2,3,4,5,6,7};intret=find_min_num(arr,sizeof(arr)/sizeof(arr[0]));cout<<"theminnumberis:"<<ret<<endl;return0;}
运行程序,输出结果为2;
可以将数组设定为不同的情况来检验。
《完》
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。