假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
请找出其中最小的元素。
你可以假设数组中不存在重复元素。
示例 1:
输入: [3,4,5,1,2]
输出: 1
示例 2:
输入: [4,5,6,7,0,1,2]
输出: 0
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思考
这题遍历其实也能通过,但复杂度是O(n),有序,我们就可以用二分。
首先,检查他有没有反转,没有的话,最小值就是nums[0]。
如果反转的话,我们需要找到反转点的位置。
[7,8,1,2]反转发生在8,1之间。
如果1当反转点,那么他前面的数比他大。
如果8当反转点,那么他后面的数比他小。
为什么能用二分查找?
1.我觉得首先基本有序
2.就是知道,二分之后,舍弃哪个区间。
首先让mid = (left + right) /2
判断mid是不是反转点:
(下方红色代表mid)
mid值<mid-1值,返回mid , 8,1
mid值>mid+1值,返回mid+1 8,1
不然所小区间
如果mid值>left,说明对应的就是[3,4,5,6,7]这个大值递增的区间,反转值应该在右边,left = mid +1
否则,对应的应该是类似这样的[6,7,1,2,3,4],反转值应该在左边,right = mid -1
下面走一遍
首先左边这个图:
mid = 6,
mid>mid+1?,不大于
mid < mid -1?,不小于
所以缩小区间
mid > left ?大于,说明左边都是递增的,反转点在右边,left = mid +1
重新计算mid
现在mid > mid+1?大于,所以返回nums[mid+1] = 1
再看右边
mid> mid +1? 不大于
mid < mid-1? 不小于
缩小区间
mid > left? 不大于,说明最小值在左边,right = mid-1
重新计算mid
mid > mid+1吗? 8>1,返回mid+1的值
代码实现
/**
* @param {number[]} nums
* @return {number}
*/
var findMin = function(nums) {
//只有一个元素
if (nums.length === 1) {
return nums[0]
}
let left = 0
let right = nums.length - 1
//检查链表是否反转过
if (nums[left] < nums[right]) {
return nums[0]
}
while(left <= right) {
let mid = Math.floor((left + right)/2)
//mid是反转点的2种情况
//1.大于后面一个
if (nums[mid] > nums[mid+1]) {
return nums[mid+1]
}
//2.小于前面一个
if (nums[mid] < nums[mid-1]) {
return nums[mid]
}
//重新选新的中点,大于左边,说明处于大的那个升序,反转点应该在右边,left变大
if (nums[mid] > nums[left]) {
left = mid + 1
}else {
//小于左边,说明经过了最小的点,反转点应该在左边,right变小
right = mid - 1
}
}
};
知识:
1.二分查找对象要是有序的表,而且你要知道缩小区间后可以舍弃哪一部分。