题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。(牛客网题目)
分析
这道题可以很简单地遍历一次,即可得答案,时间复杂度为O(n),但是没有用到旋转数组的特性,结合旋转数组特性考虑,有以下几种情况:
1、按照NOTE,数组长度为0时,返回0;
2、数组长度为1时,返回这个唯一元素就好;
3、array[ 0 ] < array[ array.length - 1 ],说明
数组没有旋转,直接返回第一个元素
4、数组中没有重复元素,如题目中给的,数组经过旋转后,前后两段子数组都是有序的,可以用类似于二分查找的方法解决,一开始声明一个下标low指向第一个元素,high指向最后一个元素,取它俩中间数(坐标为middle)分别比较,若array[ middle ]大于
array[ low ],说明
array[ middle ]属于前一个子数组,则将middle赋给low;否则,若
array[ middle ]小于
array[ high ]
,说明
array[
middle ]属于后一个子数组,则将middle赋给high,如此循环,low最终将指向前一个子数组的最后一个元素(题目中数组元素5),high将指向后一个子数组的第一个元素(题目中的1),而high指向的这个元素就是最小元素。O( lgn )
5、数组中有重复元素,如{3,3,3,2,3},第一次循环low、middle、high指向的元素都相同,这时我们还是需要遍历low、与high之间的各数,找到最小元素。O( n )
代码如下:
function minNumberInRotateArray(rotateArray)
{
// write code here
if(rotateArray.length <= 1)return rotateArray.length <= 0 ? 0 : rotateArray[0];//情况1、2
if(rotateArray[low] < rotateArray[high])return rotateArray[low];//情况3
//正常情况(如题目中数组),或者有相等元素的数组
var low = 0;
var high = rotateArray.length - 1;
var middle;
while(high - low >= 1){
if(high - low === 1){//当两个下标相邻时,high指向的就是最小元素
break;
}
middle = parseInt((low + high) / 2);
if(rotateArray[low] === rotateArray[middle] && rotateArray[middle] === rotateArray[high]){//情况5
var result = rotateArray[low];
for(var i=low;i<high;i++){
if(rotateArray[i] > rotateArray[i+1])
result = rotateArray[i+1];
}
return result;
}else if(rotateArray[low] <= rotateArray[middle])//中间值大于等于左边 {3,3,3,1,2}
low = middle;
else if(rotateArray[middle] <= rotateArray[high])//中间值小于等于右边 {3,3,1,1,1}
high = middle;
}
return rotateArray[high];//情况4
}
值得一提的是,代码22行与24行一定不要落下“=”号,否则会漏掉部分情况,导致low与high无变化,从而进入死循环。具体示例数组见代码后的注释。