题目描述:一个排序好的数组,经过数次旋转(其实就是移位),得到一个数组,找出数组中的最小值。

比如​​[1,2,3,4,5]​​​,旋转一次(往右移位1次),得到​​[5,1,2,3,4]​​​,旋转3次,得到​​[3,4,5,1,2]​

得到的新数组,满足这样的性质:以最小值的位置为分界点,左侧部分单调递增,右侧部分也单调递增,但左侧的元素,皆大于右侧的元素。

题目要求时间复杂度为 O ( l o g ( n ) ) O(log(n)) O(log(n)),而由于数组是部分有序,则很容易想到二分,关键是二分的条件。

LeetCode 153. 寻找旋转数组的最小值_二分

如上图所示,我们要二分的区间,以中间的最小值为分界线,左侧是较大的部分,右侧是较小的部分。我们每次二分,取得中点​​mid​​,这个点要么落在左侧区间,要么落在右侧区间。

当​​mid​​​落在左侧较大的区间时,我们应该往右侧搜索,此时更新左边界​​l = mid + 1​

当​​mid​​​落在右侧较小区间时,我们应该往左侧搜索,此时更新右边界​​r = mid​​​(​​mid​​本身可能是答案)

如此就比较清楚了,我们只需要判断出​​mid​​是位于左侧较大的区间,还是右侧较小的区间即可。

这就比较简单了,只需要比较​​mid​​​位置的数,和左右边界​​l​​​,​​r​​位置的数,之间的大小即可。

若​​mid​​​落在左侧较大区间,则一定有​​nums[mid] > nums[r]​

若​​mid​​​落在右侧较小区间,则一定有​​nums[mid] < nums[l]​

代码如下:

class Solution {
public int findMin(int[] nums) {
int l = 0, r = nums.length - 1;
while (l < r) {
int mid = l + r >> 1;
if (nums[mid] > nums[r]) l = mid + 1;
else r = mid; // 直接else即可
}
return nums[l];
}
}

LeetCode 153. 寻找旋转数组的最小值_搜索_02

另一道类似的题:LeetCode.33 ,与本题搜索最值不同,33这道题是搜索一个给定的目标值,二分条件的处理上要更难一些。(33这道题也是我先前字节二面的题,参考这篇文章 -> 面试记录)