一、题目
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1
样例1:
输入: [3,4,5,1,2]
输出: 1
样例2:
输入: [2,2,2,0,1]
输出: 0
二、题解
这题两个方法,第一种方法是最容易想到的就是直接遍历数组找那个断点,第二种则是二分法,速度相比更快,但是逻辑更复杂,我们具体来解析一下:
1.常规遍历法:就是遍历数组,然后找到前一个值突然大于后面个值的状况,也就是numbers[i]>numbers[i+1]的情况,这时候那个最小值(断点)就是numbers[i+1]。具体来说样例1,就是3,4,5,1,2,遍历到5之前,前面都是递增的,然后下一个值突然出现了1,发现5>1,所以可得1就为断点,输出即可,然后还有种特殊情况,本来就是完全递增的数组,这个时候直接输出第一个值numbers[0]即可。
2.二分法:一般用于查找数,这里用于查找断点,其实本质差不多,但是有一些小区别,用left表示范围左边,right表示范围右边,mid=Math.floor((left+right)/2),注意!!!这里要用Math.floor向下取整!因为js是弱类型,如果不用floor函数的话,mid算出来是小数!所以这里floor向下取整是为了保证mid是整数!然后循环判断,当number[mid]>numsber[right],断点就在mid右边(不可以为mid),当number[mid]<numsber[right],断点就在mid左边(且可以为mid),如果number[mid]==number[right],无法判断右边还是左边,则缩小范围:right--。二分结束后直接return numbers[left]或者numbers[right]即可。
三、代码(js)
//1.常规逻辑方法 遍历数组找断点
// /**
// * @param {number[]} numbers
// * @return {number}
// */
// let minArray = function(numbers) {
// for(let i = 0 , len = numbers.length; i < len ; i++)
// {
// if(numbers[i]>numbers[i+1])
// {
// return numbers[i+1];
// }
// }
// return numbers[0];
// };
// 2.二分法
/**
* @param {number[]} numbers
* @return {number}
*/
let minArray = function(numbers) {
let left = 0;
let right = numbers.length-1;
while(left<right)
{
//js是弱类型语言,这个mid一开始算出来是0.5!!!!需要用floor向下取整(向上取整为celi)
let mid = Math.floor((left+right)/2);
//当中间的数大于右边的数时,说明断点在mid右边
if(numbers[mid]>numbers[right])
{
left=mid+1;
}
//当中间的数小于右边的数时,说明断点在左边,且可能就是mid
else if(numbers[mid]<numbers[right])
{
right=mid;
}
//相等则用right--来缩短范围
else
{
right--
}
}
//这里二分完毕之后,left和right其实是一样的
return numbers[left];
};
四、拓展思考
提二分法中的几个点:
1.let mid = Math.floor((left+right)/2)这地方以后记得一定要加floor函数,js弱类型,mid会根据计算结果就变为小数了,所以必须要向下取整
2.为什么是用numbers[mid]和numbers[right]比较而不是用numbers[mid]和numbers[left]比较?举个例子,比如[1,2,3,4,5]和[5,6,7,1,2,3],显然numbers[mid]都>numbers[left],但是一个断点在左边,一个断点在右边,无法判断。
3.为什么一个numbers[mid]>numbers[right]判断之后是left=mid+1,而numbers[mid]<numbers[right]之后是right=mid?(也就是为啥left=mid还要加一?)因为当numbers[mid]>numbers[right]时,断点一定不是numbers[mid],因为断点肯定小于numbers[right],所以这时候left=mid+1。反之,当numbers[mid]<numbers[right]时,断点可能就是mid,所以right=mid。
4.为什么numbers[mid]==numbers[right]时要right--,这里原因比较复杂,想具体了解可以去leetcode的题解里面看看,链接就在下面。我的理解就是当numbers[mid]==numbers[right]时就无法判断断点是在左边还是在右边,那就无法将mid赋值left或者right,所以就只好缩小范围,所以就用right--。
题目来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/xu…