题目:把一个递增数组的前几个元素移动到数组的末尾,我们称之为数组的旋转。输入一个递增排序数组的旋转,输出旋转数组的最小元素。例如输入3 4 5 6 7 1 2,则最小元素为1。规定递增元素是没有重复元素的。
分析:
1. 最简单做法是从头到尾遍历数组,就可以求出最小元素。时间复杂度O(n),但是这个是最朴素的方法。
2. 根据旋转数组的性质,旋转数组满足“递增-最小值-递增”的性质。利用这个性质我们可以比较快速的求出最小元素。例如3 4 5 6 7 - 1 - 2,就是满足递增-最小值-递增
具体的做法是设置两个指针p1和p2,初始化分别指向数组的头和尾,然后比较两个指针所指的值和两个指针中间位置的值的关系。mid = (p1+p2) >> 1;
(1)如果arr[mid] > arr[p2],说明最小元素在mid之后则p1 = mid
(2)如果arr[mid] < arr[p2],说明最小元素在mid之前则p2 = mid
(3)如果两个指针相差为1的时候,最小值即为最小元素
时间复杂度为O(logn),因为每次可以跳到中间位置,类似二分搜索。
3. 举例旋转数组3 4 5 6 7 1 2
第一次p1指向3,p2指向2,mid指向6,发现arr[mid] > arr[p2]说明最小元素在mid之后,则p1 = mid
第二次p1指向6,p2指向2,mid指向7,发现arr[mid] > arr[p2]说明最小元素在mid之后,则p1 = mid
第三次p1指向7,p2指向2,mid指向1,发现arr[mid] < arr[p2]说明最小元素在mid之前,则p2 = mid
第四次p1指向7,p2指向1,此时p1和p2差1,则最小元素为1.
4. 代码
#include<iostream> #include<algorithm> using namespace std; //求最小元素 int GetMinNum(int *arrNum, int n){ //不合法数据 if(arrNum == NULL || n <= 0){ return -1; } int left = 0; int right = n-1; while(left < right){ if(right == left+1){ return min(arrNum[left], arrNum[right]); } int mid = (left+right)>>1; if(arrNum[mid] > arrNum[right]){ left = mid; } else{ right = mid; } } } int main(){ int arrNum[] = {3,4,5,6,7,1,2}; int value = GetMinNum(arrNum, 7); cout<<value<<endl; //输出1 return 0; }