需求:
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
数据范围:100001≤n≤10000,数组中任意元素的值: 0≤val≤10000
要求:空间复杂度:O(1) ,时间复杂度:O(logn)
输入:[3,4,5,1,2]
返回值:1
输入:[3,100,200,3]
返值:3
实现:
刚看到题的时候,我寻思这是啥玩意?脑子也很乱,今天重新捋顺,算是过了提交,如果逻辑上有些问题还请各位大佬批评指正。
旋转数组的特性:
①包含两个有序序列;
②最小数一定位于第二个序列的开头;
③前序列的值都>=后序列的值
二 分 法
1.定义 l 和 r 两个指针分别指向数组rotateArray[0](第一序列的开头)和rotateArray[rotateArray.length-1](第二序列的结尾);
2.判断该数组是否为旋转数列:rotateArray[l]>=rotateArray[r],由于默认的例子有不符合旋转数组的情况,所以单列一份首尾的判断rotateArray[l]<rotateArray[r]
3.循环二分: 设 m =Math.floor((r+l)/2) 为每次二分的中点,判断m的位置。
m大于l,则m位于前面的递增子数组,此时最小元素位于m的后面。我们可以让l指向m。移动之后,l仍然位于前面的递增数组中。
m小于r,则m位于后面的递增子数组,此时最小元素位于m的前面。我们可以让r指向m。移动之后,r仍然位于后面的递增数组中。
当 l 和 r 相邻时,最小值为rotateArray[r],循环结束。
4. 当[1,1,1,4,1,1,1,1,1]这种情况出现时,我们没法确定m的位置,定义一个方法Min()来确定最小值。
function minNumberInRotateArray(rotateArray) {
let l = 0;
let r = rotateArray.length - 1;
let m = 0;
// 先判断首尾
if (rotateArray[l] < rotateArray[r]) {
return rotateArray[l];
}
// 确定是旋转数组
while (rotateArray[l] >= rotateArray[r]) {
if (r - l === 1) {
break;
}
// 判断m是在前半段还是后半段
m = Math.floor((l + r) / 2);
if (rotateArray[l] == rotateArray[m] || rotateArray[r] == rotateArray[m]) {
return Min(rotateArray);
}
// 前
if (rotateArray[l] < rotateArray[m]) {
l = m;
}
// 后
else if (rotateArray[r] > rotateArray[m]) {
r = m;
}
}
return rotateArray[r];
}
function Min(arr) {
let min = arr[0];
for (let i = 1; i < arr.length; i++) {
if (arr[i] < min) {
min = arr[i];
}
}
return min;
}
module.exports = {
minNumberInRotateArray: minNumberInRotateArray,
};
直 接 遍 历 法
function minNumberInRotateArray(rotateArray)
{
// write code here
// 数组从左向右查
for(var i=0; i<rotateArray.length-1;i++){
// 如果,前一个 > 后一个,则后一个为最小元素
if(rotateArray[i+1]<rotateArray[i])
return rotateArray[i+1];
}
// 如果到数组末尾,依然没有前一个 > 后一个出现,则第一个为最小元素。
return rotateArray[0];
}
module.exports = {
minNumberInRotateArray : minNumberInRotateArray
};