把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [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
方法一:
分析:先让数组排序,然后再取第一个元素
Array.sort()
对数组元素进行排序
概要
array.sort()
array.sort(orderfunc)
参数
orderfunc:
用来指定如何排序的可选函数
返回值
该数组的引用。注意是在原数组中进行排序,没有新建数组
描述
sort()方法在原数组中对数组元素进行排序,没有创建新数组。如果在调用sort()时不带参数,将按字母顺序(更精确地说,是字符编码顺序)对数组中的元素进行排序。要实现这一点,首先要把元素转化为字符串(如果有必要的话),以便进行比较
如果想按照其他顺序来进行排序,就必须提供比较函数,该函数要比较两个值,然后返回一个数字来表明这两个值的相对顺序。比较函数需要接受两个参数a和b,并返回如下值
- 一个小于0的值。在这种情况下,表示根据排序标准,a小于b,在排序后的数组中,a应该排列在b的前面
- 0。在这种情况下,a和b是相等的
- 一个大于0的值。在这种情况下,a大于b。
注意:数组中的undefined元素会始终排列在数组末尾。即便提供了自定义的比较函数,也是如此,因为underfined值不会传递给提供的orderfunc。
示例
下面的代码展示了如何书写一个比较函数,来使得对一个数值按数值排序,而不是按字母排序:
//用于数值排序的排序函数
function numberorder(a,b){ return a-b}
a=new Array(33,4,222,1111);
a.sort();//字母排序:1111,222,33,4
a.sort(numberorder);//数值排序:4,33,222,1111
代码
/**
* @param {number[]} numbers
* @return {number}
*/
var minArray = function(numbers) {
return numbers.sort(function(a,b){
return a-b
})[0]
};
方法二:
分析:使用二分法来遍历数组
思路:
- 取数组
left
与right
之间的中点mid
,left
为0,right
为数组长度-1,mid
向下取整 - 让
numbers[mid]
与numbers[right]
比较(这里为什么不能让numbers[mid]
与numbers[left]
比较?原因很简单,举个例子:给出两个旋转数组[1,1,1,0,1]
,[2,0,2,2,2]
,对于这两个数组,第一个数组的最小值0
位于mid
与right
的区间,第二个数组的最小值0
位于left
与mid
的区间,单从这两个数组来看,就不能很好得看出最小值在哪个区间,所以选择让numbers[mid]
与numbers[left]
作比较) - 如果numbers[mid]>numbers[right],说明最小值在数组
mid
和right
之间的区间,让left
=mid+1
- 如果numbers[mid]<numbers[right],说明最小值在数组
left
和mid
之间的区间,让right
=mid
- 如果numbers[mid]==numbers[right],不能判断最小值在哪个区间
这个时候需要让right自减
,即缩小数组区间范围,提高精度(为什么不让left自增?
如果让left自增,遇到[1,0,1,1,1]这种数组,如下图)
这时候你如果还要让left自增,就会错过答案了,所以必须要让right自减
代码
/**
* @param {number[]} numbers
* @return {number}
*/
var minArray = function(numbers) {
let left=0;
let right=numbers.length-1;
while(left<right){
//向下取整
let mid=Math.floor((left+right)/2);
if(numbers[mid]<numbers[right]){
right=mid;
}else if(numbers[mid]==numbers[right]){
right--
}else{
left=mid+1
}
}
return numbers[left]
}