题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个 非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思路
本题最简单的做法就是从头到尾的遍历。这样一定可以得到结果,只是这样操作的时间复杂度是O(n)。没有利用上旋转这个题目特性。正确的思路是,利用二分查找的思想。让一个begin下标表示数组的开始,一个end下标表示数组的结束,mid表示数组的中间值。通过三者值的比较得到范围。如果mid的值大于begin的值,说明最小值的范围在mid到end之间。反之在begin到mid之间。依次缩小范围,直到找到最小值。
注意
1、存在一种情况,并没有旋转。也就是数组的第一个元素就是最小值。可以通过比较一开始begin和end的值判断,如果begin的值小于end的值,那么直接返回begin的值即可。
2、判断停止的条件是当begin的下一个值就是end的时候,这个时候end一定是最小值。因为begin已经到达最大值,end自然是最小值了。
3、判断的时候请注意重复值的情况。如果出现一种情况,begin、mid、end对应的值都一样。这个时候就需要用遍历的思路来执行查找。
4、需要注意边界值的判断,如果边界值的判断出问题,可能会出现死循环。
代码
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
if(rotateArray.size() == 0)
return 0;
int size = rotateArray.size();
int begin = 0;
int end = size - 1;
int mid = 0;
while(rotateArray[begin] >= rotateArray[end]){
if(begin+1 == end){
mid = end;
break;
}
mid = begin + (end-begin)/2;
if(rotateArray[mid] == rotateArray[begin] &&
rotateArray[mid] == rotateArray[end])
return MinNumber(rotateArray, begin, end);
else if(rotateArray[mid] >= rotateArray[begin])
begin = mid;
else if(rotateArray[mid] <= rotateArray[end])
end = mid;
}
return rotateArray[mid];
}
int MinNumber(const vector<int>& arr, int begin, int end){
int result = begin;
for(int i = result+1; i <= end; ++i){
if(arr[i] > arr[result])
break;
result = i;
}
return arr[result];
}
};