目录
题目: 旋转数组的最小数字
- 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
- 给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为 1。
- 注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
- 提示:
- n == numbers.length
- 1 <= n <= 5000
- -5000 <= numbers[i] <= 5000
- numbers 原来是一个升序排序的数组,并进行了 1 至 n 次旋转
题解一:管他三七二十一,求最小值
- 思路:看不懂题目。。不就是求最小值。上来就求最小值(可行!)但辜负出题人的好意(考点)。据说这还是字节面试题,你总不可能直接说求最小值吧。。。
- 代码:
/**
* @param {number[]} numbers
* @return {number}
*/
var minArray = function(numbers) {
numbers.sort((a,b)=>a-b);
return numbers[0];
};
题解二:暴力突破
- 思路:
- 数组是递增数组(前提)
- 发现旋转数组在旋转后,有个分界点,而这个分界点就是最小的那个数
- 利用遍历找到分界点(即是突然变小的值)
- 代码:
/**
* @param {number[]} numbers
* @return {number}
*/
var minArray = function(numbers) {
for(let i=0;i<numbers.length;i++){
if(numbers[i]>numbers[i+1]){
return numbers[i+1];
}
}
return numbers[0];
};
- 复杂度分析:
- 时间复杂度:O(n)
- 空间复杂度: O(n)
题解三:二分法(推荐)
-
思路:二分法注意边界
- 形成思路模式:有序->想到二分法
- 1首先,创建两个指针 left, right 分别指向 numbers首尾数字,然后计算出两指针之间的中间索引值 mid,然后我们会遇到以下三种情况:
- mid > right :代表最小值一定在 mid 右侧,所以 left移到 mid + 1的位置。
- mid< right :代表最小值一定在 mid 左侧或者就是 mid,所以 right 移到 mid的位置。
- mid既不大于 left 指针的值,也不小于 right指针的值,代表着 mid 可能等于 left指针的值,或者 right 指针的值,我们这时候只能让 right 指针递减
- 最后返回
Math.min(numbers[left],numbers[right])
-
代码:
/**
* @param {number[]} numbers
* @return {number}
*/
var minArray = function(numbers) {
let left= 0;
let right = numbers.length-1;
while(right-left>1){
let mid = left+((right-left)>>1);
if(numbers[mid]>numbers[right]){
left = mid+1;
}
else if(numbers[mid]<numbers[right]){
right = mid;
}
else{
right--;
}
}
return Math.min(numbers[left],numbers[right]);
};
- 复杂度分析:
- 时间复杂度:O(logn)