153. Find Minimum in Rotated Sorted Array
题目
Suppose an array of length n sorted in ascending order is
rotatedbetween1andntimes. For example, the arraynums = [0,1,2,4,5,6,7]might become:
[4,5,6,7,0,1,2]if it was rotated 4 times.
[0,1,2,4,5,6,7]if it was rotated 7 times.
Notice that rotating an array
[a[0], a[1], a[2], ..., a[n-1]]1 time results in the array[a[n-1], a[0], a[1], a[2], ..., a[n-2]].
Given the sorted rotated array
numsofuniqueelements, return the minimum element of this array.
You must write an algorithm that runs in
O(log n)time.
传入一个 数字阵列 nums,所有的数字都是唯一不会重複的,这个数字阵列的数字是从小到大递增排序,但阵列会被旋转 n 次
| 数字阵列 nums | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| 旋转 1 次 | 5 | 1 | 2 | 3 | 4 |
| 旋转 2 次 | 4 | 5 | 1 | 2 | 3 |
| 旋转 3 次 | 3 | 4 | 5 | 1 | 2 |
| 旋转 4 次 | 2 | 3 | 4 | 5 | 1 |
| 旋转 5 次 | 1 | 2 | 3 | 4 | 5 |
当旋转到第 n 次会恢復原状,每次会旋转几次不一定,尝试找出数字阵列 nums中最小的整数
Example
Input: nums = [3,4,5,1,2]
Output: 1
Explanation: The original array was [1,2,3,4,5] rotated 3 times.
Input: nums = [4,5,6,7,0,1,2]
Output: 0
Explanation: The original array was [0,1,2,4,5,6,7] and it was rotated 4 times.
Input: nums = [11,13,15,17]
Output: 11
Explanation: The original array was [11,13,15,17] and it was rotated 4 times.
演算法
1. 二分法切割要检查的数字索引范围
设定左右指标,匡选检查的范围
- 左边指标: 0,数字阵列最左方索引
- 右边指标: 数字阵列最右方索引,全部的版本号数字
取左右指标索引,左右逼近到可能出现的最接近的数字,如果「左边数字索引」与「右边数字索引」没有相交,表示还可以再寻找
将数字索引位置切割成一半,拿左右字母索引的平均数当作切割点,可以把数字切割成一半,减少要检查的范围
2.「中间指标数字」与「右指标数字」比较
状况 A. 如果「中间指标数字」小于等于「右指标数字」
表示「右边」的数字序列是较大的序列
要找最小的数字需要往「左边」找
将「右指标」设定为目前的「中间指标」,再继续检查
状况 B. 如果「中间指标数字」大于「右指标数字」
表示「左边」的数字序列是较大的序列
要找最小的数字需要往「右边」找
将「左指标」设定为目前的「中间指标」,再继续检查
3. 确认最小数字在左指标
因为「左指标」会不断地往右移动,然后一直确保「左指标」的左边一定是较大的数字
所以最后左指标指定的数字,为最小的数字
答案
JavaScript
function findMin(numberList) {
// 左指标
var leftPointer = 0;
// 右指标
var rightPointer = numberList.length - 1;
while (leftPointer < rightPointer) {
// 当「左指标」还没超过「右指标」,表示还没比完,可以继续比较
// 将检查的指标切半,用「中间指标」当作参考指标
var middlePointer = leftPointer + Math.floor((rightPointer - leftPointer) / 2);
// 「中间指标」的数字
var middleNumber = numberList[middlePointer];
// 「右指标」的数字
var rightNumber = numberList[rightPointer];
// 「中间指标数字」与「右指标数字」比较
if (middleNumber <= rightNumber) {
// 如果「中间指标数字」小于等于「右指标数字」,表示「右边」的数字序列是较大的序列
// 要找最小的数字需要往「左边」找
// 将「右指标」设定为目前的「中间指标」,再继续检查
rightPointer = middlePointer;
}
else {
// 如果「中间指标数字」大于「右指标数字」,表示「左边」的数字序列是较大的序列
// 要找最小的数字需要往「右边」找
// 将「左指标」设定为目前的「中间指标」,再继续检查
leftPointer = middlePointer + 1;
}
}
// 因为「左指标」会不断地往右移动,然后一直确保「左指标」的左边一定是较大的数字
// 所以最后左指标指定的数字,为最小的数字
return numberList[leftPointer];
}
TypeScript
function findMin(numberList: number[]): number {
// 左指标
let leftPointer: number = 0;
// 右指标
let rightPointer: number = numberList.length - 1;
while (leftPointer < rightPointer) {
// 当「左指标」还没超过「右指标」,表示还没比完,可以继续比较
// 将检查的指标切半,用「中间指标」当作参考指标
let middlePointer = leftPointer + Math.floor((rightPointer - leftPointer) / 2);
// 「中间指标」的数字
let middleNumber: number = numberList[middlePointer];
// 「右指标」的数字
let rightNumber: number = numberList[rightPointer];
// 「中间指标数字」与「右指标数字」比较
if (middleNumber <= rightNumber) {
// 如果「中间指标数字」小于等于「右指标数字」,表示「右边」的数字序列是较大的序列
// 要找最小的数字需要往「左边」找
// 将「右指标」设定为目前的「中间指标」,再继续检查
rightPointer = middlePointer;
} else {
// 如果「中间指标数字」大于「右指标数字」,表示「左边」的数字序列是较大的序列
// 要找最小的数字需要往「右边」找
// 将「左指标」设定为目前的「中间指标」,再继续检查
leftPointer = middlePointer + 1;
}
}
// 因为「左指标」会不断地往右移动,然后一直确保「左指标」的左边一定是较大的数字
// 所以最后左指标指定的数字,为最小的数字
return numberList[leftPointer];
};