力扣第162题-寻找峰值

200 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第24天,点击查看活动详情

前言

力扣第162题 寻找峰值 如下所示:

image.png

一、思路

题目的意思很简单,找到数组中的某一个峰值,满足 nums[i] > nums[i-1]nums[i] < nums[i+1]。此外提示中还有两个重要的信息:

  1. nums[i] != nums[i+1],也就是说相邻的两个元素是不相等的。
  2. nums[-1] = nums[n] = -∞

既然要找到数组的峰值,一个非常简单朴素的想法为:一次遍历数组中的所有元素,如果某个元素 nums[i] 满足条件则返回该下标 i。但是这样的时间复杂度为 O(N),不能满足题目中时间复杂度 O(logN)

说道时间复杂度 O(logN),很容易就能联想到使用 二分法。我们不妨假设某次二分后左右边界内的数组如下所示:

image.png

nums[mid] 会有如下的三种情况

  1. nums[mid] 在上升区间

此时出现了 nums[mid+1] > nums[mid],出现了上升的趋势,在 mid 的右边一定会出现峰顶。所以丢弃mid靠左的元素即可,即 left = mid+1

提示:即使 mid 往后都是升序的,也会在 n-1 出现峰顶。因为 nums[n]为负无穷

image.png

  1. nums[mid] 在下降区间

此时出现了 nums[mid+1] < nums[mid],出现了上升的趋势,在 mid 的左边一定会出现峰顶。所以丢弃mid靠右的元素即可,即 right = midmid下标不能丢弃)

image.png

  1. nums[mid] 在峰顶,此时直接返回结果即可

综上所述,二分法 的思路为:mid 处于上升期则丢弃左边,如mid 处于下降期则丢弃右边

二、实现

实现代码

实现代码与思路中保持一致

public int findPeakElement(int[] nums) {
    int left = 0;
    int right = nums.length - 1;
    while (left < right) {
        int mid = (left + right) / 2;
        if(nums[mid] < nums[mid + 1]){
            left = mid + 1;
        }else{
            right = mid;
        }
    }
    return left;
}

测试代码

public static void main(String[] args) {

    int[] nums = {1,2,1,3,5,6,4};
    new Number162().findPeakElement(nums);
}

结果

image.png

三、总结

感谢看到最后,非常荣幸能够帮助到你~♥

如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~