难度中等743
峰值元素是指其值严格大于左右相邻值的元素。
给你一个整数数组 nums
,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞
。
你必须实现时间复杂度为 O(log n)
的算法来解决此问题。
提示:
1 <= nums.length <= 1000
-231 <= nums[i] <= 231 - 1
对于所有有效的 i 都有 nums[i] != nums[i + 1]
从思维反射的角度去讲解
PS:注意看文章的 区间 的 ( [ 取值 !!!!!!!
题目一开始需要logN时间复杂度,则可知这题需要二分求解。
可能有小伙伴会陷入于01(有 和 没有)的二分泥潭中,导致这道题最终还是没能太明白。
其实只需要抓住题目最重要的两点:(这里很重要)
设 左边界 i = 0, 右边界 j = n - 1 (这是初始化的值,会变动的!但是不论怎么变动 依然要满足 Num[i] > Num[i-1], 要满足 Num[j] > Num[j+1])
-
nums[-1] = nums[n] = -∞,通俗的说 以 i = 0开始的递增数组区域 ,峰值是Num[0] 以 j = n-1 结束的递减数组区域,峰值是Num[n-1]。
-
如果 以 i开始 或 j结束 的区域不是有序的,则当中必有峰值!(因为无序,下标i 到 下标j 的数组值连成一条线是肯定有起伏的)
设 下标 t 在 (0, n-1) 区间 内
由上面两点 得出结论
- [ i , t )递减 or 无序 必定有峰值--(也就是说以0开始的区域 只有递增是 不可能有峰值的)
- ( t , j ] 递增 or 无序 必定有峰值--(也就是说以n-1结束的区域 只有递减是 不可能有峰值的)
把思路串起来~
所以 看到这里 一定要明白!既然有的区域一定存在峰值 我们肯定是要找一定有峰值的区域!可能有峰值的 区域咱们不找 如果找不到 岂不是白找了吗。
设 : i= 0, j= n - 1 ,mid = ( i + j ) / 2
1. nums[mid] > nums[mid + 1]时候 ,以下是所有情况↓
- 在(mid , j] 可能存在递减,这里就呼应了上面说的 递减是不可能有峰值的!(也有可能不是递减,但是既然存在有递减的可能,就不找了呗!找不到咋办)
- 在 [i , mid] 肯定是存在峰值的。这时候有人会说了,“既然不能确定 这个区域是递减 和 无序 也就不能确定这个区间 是有还是没有峰值的!”那你要想想啦,既然我们已经知道( mid , j )是不存在的 所以我们肯定不找那里呀,所以肯定找这里呀,有人觉得不严谨,那我们就假设,[i,mid) 是递增,这时候 在 [ i , mid)肯定肯定没有峰值!那么显而易见 峰值就是mid啦。所以这个区域必定存在峰值
2.nums[mid] < nums[mid + 1] 时候 ,以下是所有情况↓
- 在(mid , j ] 肯定存在峰值,呼应上面的 分析的递增 or 无序情况。此没有递减情况,因为已经nums[mid] < nums[mid + 1]...
- 在[ i , mid] 是不可能存在峰值的, 呼应上面分析的递减 or 无序情况。可以自己分析一下哈
有小伙伴回问?没有 == 的情况?? 拜托!写题请一定要全部审好题!!题目已经说明不存在相等的情况,那么如果存在前后相等的情况,那么上面的结合就会失效了。正因为有了元素前后不相等的情况 才不会存在 没有峰值的情况!
class Solution {
public int findPeakElement(int[] nums) {
int left = 0, right = nums.length - 1;
while (left < right) {
int mid = left + right >> 1;
if (nums[mid] > nums[mid + 1]) {
right = mid;//mid要留,因为 mid 满足其中一个条件 nums[mid] > nums[mid + 1],可能这个峰值就是mid
} else {
left = mid + 1; //mid留不了,已经不大于邻值了
}
}
return left;
}
}