因为给出了复杂度要求,可以想到使用二分法。
但是关键就在于二分的那个点.
nums[mid]可能大于左边或者大于右边的数,也可能小于左边或者右边的数,我们来讨论一下具体的情况
- nums[mid]小于左边或者右边的某一个数,或者小于两边的数。
- nums[mid]大于左右两边的数。
对于情况二,就是要找的峰值。
而对于情况1,我们的二分查找接下来倒底是往左边还是右边查找呢?
我们假定右边的数大于当前的nums[mid]
那么我们一定在右边可以找到峰值!(左边也可能找到)原因如下:
对于右边剩下的数,不管是递增还是递减,还是无序(也就是随意排列),那么总会有一个最大的数。
那么这个数肯定大于左右两边的数(即使这个数是mid+1这个位置的。注意nums[n]=负无穷)。
而如果此时我们选择查找左边,如果最大值不是mid-1这个的话,那也能找到驼峰,但是如果不幸是的话,那就gg了。
可以画折线图来演示
class Solution {
public int findPeakElement(int[] nums) {
int n = nums.length;
int idx = 0;
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r >> 1;
//一直往大的那块区域查找,按照之前的所说的,一定存在峰值
if ((mid + 1 < n && nums[mid] < nums[mid + 1])) {
l = mid+1;
}
//else有两种情况:左边可能也是大的那块区域,或者当前mid就是峰值,
//那么r=mid,左边也一定有峰值
else {
r = mid;
}
}
return l;
}
}
代码这里不用担心越界的情况,因为其实我们利用else避免了越界,同时其实mid+1<n也不需要判断了,因为我们l+r>>1会使得mid一定小于n-1(l=r=n-1时才可能使mid为n-1)