leetcode_162:寻找峰值

这个题目主要是弄懂峰值出现的时候会有哪些情况,事情就会简单很多。所以遇到题的时候,还是要冷静思考问题的关键所在

首先我们要注意到问题中的一个特点:你可以假设nums[-1] = nums[n] = -∞,所以两边的肯定都是极小值。那我们可以从nums[0]开始向后遍历,会出现3种情况:

  1. 数组一直是递减的。如下图所示:那么此时的峰值就是Num是[0]。
    在这里插入图片描述
  2. 数组一直是递增的,那么峰值就是nums[nums.length - 1]
    在这里插入图片描述
  3. 数组是不规则的。通过前面其实我们能得出一条规律或者寻找的方法:我们沿着数组递增的方向寻找,直到遇到一个数字它的后面是递减的,那么这个值就是峰值。因为我们保证了前面的序列都是递增的,也就是此元素肯定大于前面的值,然后又在后面遇到一个比它小的值,那么它就一定是峰值了。比如情况1,那么第一个就是等着;情况2,最后一个是峰值;那这种不规则的情况也就是这样找的。如图所示
    在这里插入图片描述

1. 循环遍历

那么问题就变得简单了,我们只需要按照情况3里的思路遍历数组,直到找到符合条件的元素为止。代码如下:

public class Solution {
    public int findPeakElement(int[] nums) {
        for (int i = 0; i < nums.length - 1; i++) {
            if (nums[i] > nums[i + 1])
                return i;
        }
        return nums.length - 1;
    }
}

2. 二分查找

当然题目还要求时间复杂度为 O(logN)的,所以一定想到了二分查找。我们把一个数组看成是交替的升序和降序序列,每次我们找到一个mid,然后判断它在哪种序列中(通过与右边的元素比较)。如果它在升序的序列中(nums[mid] < nums[mid+1]),那么一定存在一个峰值是在mid的右边的,因为我们有个假设条件nums[-1] = nums[n] = -∞,这样我们就可以把寻找空间缩小到它的右边;如果它在降序的序列中(nums[mid] > nums[mid+1]),那么一定存在一个峰值可能就在它的左边(当然包括它自己,因为它本身比较大),同样也是因为刚才那个假设条件。直到这个区间缩小到为1时,也就找到了那个元素。二分查找有递归和非递归两种,分别如下:

//递归解法
public class Solution {
    public int findPeakElement(int[] nums) {
        return search(nums, 0, nums.length - 1);
    }
    public int search(int[] nums, int l, int r) {
        if (l == r)
            return l;
        int mid = (l + r) / 2;
        if (nums[mid] > nums[mid + 1])	//它是在一个下降区间,则找它的左半边
            return search(nums, l, mid);
        return search(nums, mid + 1, r);	//否则在上升区间,找它的右半边
    }
}
//非递归解法
public class Solution {
    public int findPeakElement(int[] nums) {
        int l = 0, r = nums.length - 1;
        while (l < r) {
            int mid = (l + r) / 2;
            if (nums[mid] > nums[mid + 1])
                r = mid;
            else
                l = mid + 1;
        }
        return l;
    }
}
发布了96 篇原创文章 · 获赞 2 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/reachwang/article/details/103577893
今日推荐