【2种解法】【剑指Offer】【JavaScript题解】
题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为 1。
NOTE:给出的所有元素都大于 0,若数组大小为 0,请返回 0。
专注前端与算法的系列干货分享,欢迎关注(¬‿¬):
「微信公众号:心谭博客」| xxoo521.com | GitHub
解法 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: 二分查找
看到这种题目,正确做法基本上都是需要使用二分查找。
对于这种变形的二分查找的考察,解决思路主要都是:观察 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]; }