题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1
旋转数组
经观察,旋转数组实际上可以划分为两个排序的子数组,前面数组的元素都大于或等于后面数组的元素,且最小的元素刚好是两个数组的分界符
思路
因为本题给的数组一定程度上是排序的,所以我们可以使用类似二分查找法的思路来解决问题
- 用两个指针分别指向第一个元素和最后一个元素,按题目的规则,第一个元素应该是大于或等于最后一个元素的(存在特例)
- 找出中间的元素,如果它在前面的子数组,那么它应该大于第一个指针指向的元素,此时可将第一个指针指向该中间元素,缩小寻找范围;如果它在后面的子数组,那么它应该小于第二个指针指向的元素,此时可将第二个指针指向该中间元素,缩小寻找范围
- 使用更新后的指针,进行新一轮的查找
- 经过多轮查找后,两指针最后会指向两个相邻的元素,而第二个指针刚好指向最小的元素
但若是旋转数组为{1,0,1,1,1}(原数组为{0,1,1,1,1}),此时,第一个元素和最后一个元素以及中间元素相等,无法通过上述过程找到最小元素,则只能顺序查找
代码实现
function minNumberInRotateArray(rotateArray)
{
// write code here
if(rotateArray.length === 0){
return 0;
}
var index1 = 0;
var index2 = rotateArray.length - 1;
var mid = index1;
//如果为顺序数组
if(rotateArray[index1] < rotateArray[index2]){
return rotateArray[index1];
}
while(index1 < index2){
if(index2 - index1 === 1){
return rotateArray[index2];
}
mid = (index1 + index2) >> 1;
if(rotateArray[mid] > rotateArray[index1]){
index1 = mid;
}
else if(rotateArray[mid] < rotateArray[index2]){
index2 = mid;
}
else{
if(rotateArray[mid] === rotateArray[index2]){
return Math.min(...(rotateArray.slice(index1, index2+1)));
}
else{
index1 = mid;
}
}
}
}