剑指OFFER之旋转数组的最小数字
- 题目描述:
-
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
- 输入:
-
输入可能包含多个测试样例,对于每个测试案例,
输入的第一行为一个整数n(1<= n<=1000000):代表旋转数组的元素个数。
输入的第二行包括n个整数,其中每个整数a的范围是(1<=a<=10000000)。
- 输出:
-
对应每个测试案例,
输出旋转数组中最小的元素。
- 样例输入:
-
5 3 4 5 1 2
- 样例输出:
-
1
二分法的思想:
1.如果数组内的元素实际上没有旋转,如1 2 3 4 5,那么就直接输出arr[indexMid],
这也是为什么indexMid初始化为index1的原因。
2.设置2个指针(数组下标)index1和index2,分别初始化为0和n-1;讨论:
如果index1和index2的中间值大于或者等于index1,说明中间值仍旧在第一个递增数组内,所以
把中间值的下标赋值给index1;
如果index1和index2的中间值小于或者等于index2,说明中间值在第二个递增数组内,把中间值
的下标赋值给index2;
直到index1和index2相邻的时候,index2指向的就是最小值
3.考虑特殊情况:假设序列1 0 1 1 1,这个时候按照上面的来中间值等于index1,那么会把2赋值给index1,
这样一来已经错了。同理,考虑序列1 1 1 0 1;所以当中间值既等于arr[index1]又等于arr[index2],
只好把数组遍历一遍找出最小值了。
Code:#include <iostream> using namespace std;
int OrderFind(int *arr,int n){ int result=arr[0]; for(int i=1;i<n;++i){ if(arr[i]<result){ result=arr[i]; } } return result; } int arr[1000010]; int main() { int n; while(cin>>n)!=EOF){ for(int i=0;i<n;++i){ cin>>arr[i]; } int index1=0; int index2=n-1; int indexMid=index1; bool flag=true; while(arr[index1]>=arr[index2]){ if(index2-index1==1){ indexMid=index2; break; } int indexMid=(index1+index2)/2; if(arr[index1]==arr[index2]&&arr[index1]==arr[indexMid]){ cout<<OrderFind(arr,n)<<endl; flag=false; break; } if(arr[indexMid]>=arr[index1]){ index1=indexMid; } if(arr[indexMid]<=arr[index2]){ index2=indexMid; } } if(flag==true){ cout<<arr[indexMid]<<endl; } } return 0; } /************************************************************** Problem: 1386 User: lcyvino Language: C++ Result: Accepted Time:670 ms Memory:5424 kb ****************************************************************/