题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为 1。
NOTE:给出的所有元素都大于 0,若数组大小为 0,请返回 0。
解法 1:暴力法
遍历一次,直接找到比较出最小的数字。
时间复杂度是 O(N),空间复杂度是 O(1)。
// 原文地址:https://xxoo521.com/2019-12-24-xuan-zhuan-shu-zu/
// ac地址:https://www.nowcoder.com/practice/9f3231a991af4f55b95579b44b7a01ba
/**
* @param {number[]} rotateArray
*/
function minNumberInRotateArray(rotateArray) {
const length = rotateArray.length;
if (!length) {
return 0;
}
return Math.min(...rotateArray);
}
解法 2: 二分查找
专注前端与算法的系列干货分享,欢迎关注(¬‿¬):
「微信公众号:心谭博客」| xxoo521.com | GitHub
看到这种题目,正确做法基本上都是需要使用二分查找。
对于这种变形的二分查找的考察,解决思路主要都是:观察 left、mid、right 三个指针对应的元素的大小关系,然后移动指针。
具体的解决方法主要是:多写几个例子,然后观察如何移动。
举几个例子来推导解题细节(请记住题干的数组有序、某个点旋转这两个条件):
arr[left] < arr[right]
: 直接返回arr[left]
。例如:1 2 3 4 5
arr[left] < arr[mid]
: 说明从数组下标范围为[left, right]
的元素是递增的,此时最小值只可能出现在[mid + 1, length)
范围内。例如:4 5 1 2 3
arr[mid] < arr[right]
: 说明从数组下标范围为[mid, right]
的元素是递增的,此时最小值只可能出现在[left, mid]
范围内。注意,这里不能跳过下标mid
。例如:3 3 3 4 5
- 其他情况,此时
arr[mid] = arr[right] = arr[left]
: 移动 left,缩小范围即可。例如:1 1 1 0 1
// 原文地址:https://xxoo521.com/2019-12-24-xuan-zhuan-shu-zu/
// ac地址:https://www.nowcoder.com/practice/9f3231a991af4f55b95579b44b7a01ba
function minNumberInRotateArray(rotateArray) {
const length = rotateArray.length;
if (!length) {
return 0;
}
let left = 0,
right = length - 1;
while (left < right) {
let mid = Math.floor((left + right) / 2);
// 子数组有序
if (rotateArray[left] < rotateArray[right]) {
return rotateArray[left];
}
// 左子数组有序,最小值在右边
// 那么mid肯定不可能是最小值(因为rotateArray[mid]大于rotateArray[left])
if (rotateArray[left] < rotateArray[mid]) {
left = mid + 1;
// 右子数组有序,最小值在左边
// 这里right=mid因为最小值可能就是rotateArray[mid]
} else if (rotateArray[mid] < rotateArray[right]) {
right = mid;
} else {
// 无法判断,缩小下范围
++left;
}
}
return rotateArray[left];
}
专注前端与算法的系列干货分享,欢迎关注(¬‿¬)