题目
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思路
本题的直观解法很简单,直接对数组进行一次遍历就可以找到最小值,时间复杂度为O(n),但是显然这不是本题的意图所在,因为没有利用到任何旋转数组的特性。
细想一下可以发现旋转之后的数组实际上可以划分为两个排序的子数组,而且前面排序的子数组的元素都大于或者等于后面子数组的元素,更重要的一点,最小的元素刚好是这两个子数组的分界线。在排序的数组中可以使用二分查找法,使用两个指针分别指向数组的第一个元素和最后一个元素。
首先用两个指针low和high分别指向数组的第一个元素和最后一个元素,然后可以找到中间元素mid。对于这个中间元素,有以下两种情况:(1)该元素大于等于low指向的元素,此时最小的元素说明在mid的后面,可以把low=mid;(2)中间元素小于等于high指向的元素,那么最小元素在mid之前,可以high=mid。特别注意:这里不要+1或者-1,因为只有这样才能保证low始终在第一个数组,high始终在第二个数组。依次循环,当最后low和high相差1时,low指向第一个数组的最后一个,high指向第二个数组的第一个(即为我们要找的最小值)。以上查找的时间复杂度为O(logN)。
注意:虽然上面的分析包含了绝大多数的情况,但是仍然存在一种情况是我们并未考虑的,那就是第一个指针和第二个指针的值相等,并且中间位置的值也相等,这时候我们无法判断中间位置的值是属于第一个递增数组还是第二个递增数组,所以需要使用顺序查找来获取最小值。
![](https://img-blog.csdnimg.cn/2020020100421142.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mjc2MjA4OQ==,size_16,color_FFFFFF,t_70)
JavaScript代码
function minNumberInRotateArray(rotateArray)
{
var low = 0;
var high = rotateArray.length - 1;
var mid;
if (rotateArray.length === 0) {
return 0;
} else {
while (low < high) {
mid = Math.floor((high + low)/2);
if (rotateArray[low] === rotateArray[mid] && rotateArray[high] === rotateArray[mid]) {
return minInOrder(rotateArray);
}
if (high - low == 1) {
return rotateArray[high];
}
if (rotateArray[mid] > rotateArray[low]) {
low = mid;
} else {
high = mid;
}
}
}
}
function minInOrder(arr) {
var min = arr[0];
for(var i = 0; i < arr.length; i++) {
if (arr[i] < min) {
min = arr[i];
}
}
return min;
}