题解 | #寻找峰值#

寻找峰值

http://www.nowcoder.com/practice/fcf87540c4f347bcb4cf720b5b350c76

题目主要信息:
  • 给定一个长度为n的数组,返回其中任何一个峰值的索引
  • 峰值元素是指其值严格大于左右相邻值的元素
  • 数组两个边界可以看成是最小,nums[1]=nums[n]=nums[-1] = nums[n] = -\infty
  • 峰值不存在平的情况,即相邻元素不会相等
举一反三:

学习完本题的思路你可以解决如下题目:

BM17.二分查找-I

BM18.二维数组中的查找

BM21.旋转数组

方法:二分查找(推荐使用)

知识点:分治

分治即“分而治之”,“分”指的是将一个大而复杂的问题划分成多个性质相同但是规模更小的子问题,子问题继续按照这样划分,直到问题可以被轻易解决;“治”指的是将子问题单独进行处理。经过分治后的子问题,需要将解进行合并才能得到原问题的解,因此整个分治过程经常用递归来实现。

思路:

因为题目将数组边界看成最小值,而我们只需要找到其中一个波峰,因此只要不断地往高处走,一定会有波峰。那我们可以每次找一个标杆元素,将数组分成两个区间,每次就较高的一边走,因此也可以用分治来解决,而标杆元素可以选择区间中点。

//右边是往下,不一定有坡峰
if(nums[mid] > nums[mid + 1])
    right = mid;
//右边是往上,一定能找到波峰
else
    left = mid + 1;

具体做法:

  • step 1:二分查找首先从数组首尾开始,每次取中间值,直到首尾相遇。
  • step 2:如果中间值的元素大于它右边的元素,说明往右是向下,我们不一定会遇到波峰,但是那就往左收缩区间。
  • step 3:如果中间值大于右边的元素,说明此时往右是向上,向上一定能有波峰,那我们往右收缩区间。
  • step 4:最后区间收尾相遇的点一定就是波峰。

图示:

alt

Java实现代码:

import java.util.*;
public class Solution {
    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])
                right = mid;
            //右边是往上,一定能找到波峰
            else
                left = mid + 1;
        }
        //其中一个波峰
        return right; 
    }
}

C++实现代码:

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int left = 0;
        int right = nums.size() - 1;
        //二分法
        while(left < right){ 
            int mid = (left + right) / 2;
            //右边是往下,不一定有坡峰
            if(nums[mid] > nums[mid + 1])
                right = mid;
            //右边是往上,一定能找到波峰
            else
                left = mid + 1;
        }
        //其中一个波峰
        return right; 
    }
};

Python实现代码

class Solution:
    def findPeakElement(self , nums: List[int]) -> int:
        left = 0
        right = len(nums) - 1
        # 二分法
        while left < right: 
            mid = int((left + right) / 2)
            # 右边是往下,不一定有坡峰
            if nums[mid] > nums[mid+1]: 
                right = mid
            # 右边是往上,一定能找到波峰
            else: 
                left = mid + 1
        # 其中一个波峰
        return right 

复杂度分析:

  • 时间复杂度:O(log2n)O(log_2n),二分法最坏情况对整个数组连续二分,最多能分log2nlog_2n
  • 空间复杂度:O(1)O(1),常数级变量,无额外辅助空间
全部评论
[10,5,6,7,8,9] 我不理解 为什么这个数组的峰值是9,不应该是10吗
点赞 回复 分享
发布于 2022-05-19 16:07
看一下这两句话: step 2:如果中间值的元素大于它右边的元素,说明往右是向下,我们不一定会遇到波峰,但是那就往左收缩区间。 step 3:如果中间值大于右边的元素,说明此时往右是向上,向上一定能有波峰,那我们往右收缩区间。 是我脑子坏了吗?为什么我读不懂?
5 回复 分享
发布于 2022-05-13 15:18
首先要知道题目的要求是找到任意一个峰值即可,大家很多的困惑在于:为什么右边是向上的就一定能找到峰值。因为右边是向上的会对应两种情况:1、右侧会在某个元素开始下降;2、右侧一直向上递增。第一种情况:如果右侧会在某个数组元素开始下降,那么这个数组元素就是峰值;第二种情况,如果右侧一直向上递增,这时候可能有人就会觉得那不就是没有峰值了,但是按照题目中的条件: nums[-1] = nums[n] = −∞,这时峰值就是数组的最后一个元素。
5 回复 分享
发布于 2023-07-04 11:01 福建
我觉得这道题是有问题的,尝试测试案例[1,2,1,3,3],中间值是第三个元素,小于右边的元素,按照题目意思,中间元素严格大于两侧的元素,后面的两个元素 3 都不应该是波峰,但这个案例实际存在波峰,即元素 2 。但是题解的答案是 4,也就是最后一个元素???
3 回复 分享
发布于 2022-05-15 10:18
同意一楼的说法,看不懂为啥向上就一定有波峰,感觉题解有问题啊,很明显 假如往右一直是递增的不就没有了吗
2 回复 分享
发布于 2022-06-05 12:03
题目要求是 波峰是大于两侧的值的,为啥测试用例中会有 数组 [2] 是有波峰的, 看不懂
1 回复 分享
发布于 2022-06-05 12:04
为什么二分查找大的那一半一定会有峰值呢?(即nums[mid]<nums>nums[mid],那么mid+2只有两种可能,一个是大于mid+1,一个是小于mid+1,小于mid+1的情况,那么mid+1就是峰值,大于mid+1的情况,继续向右推,如果一直到数组的末尾都是大于的,那么可以肯定最后一个元素是峰值,因为nums[nums.length]=负无穷</nums>
1 回复 分享
发布于 2022-07-11 09:07
我直接输入[1,2,3,1,1,1,1],它就会有问题,很明显对于相等的元素该算法有错误
1 回复 分享
发布于 2022-07-29 15:23
“只要不断地往高处走,一定会有波峰” 这是什么原理,没想明白呀
1 回复 分享
发布于 2022-09-08 15:51 北京
为什么题解要用右侧往上或者往下来判断,如果用左侧应该如何判断呢?
1 回复 分享
发布于 2023-07-19 00:37 广东
[2, 4, 3, 5, 6],峰值是4(第二个元素),第一次循环跟3 < 5,那就缩到右半边了,最后结果不是错了吗?最后一个6也不满足峰值的条件,峰值第一个条件:峰值元素是指其值严格大于左右相邻值的元素;6的右边没有元素。
点赞 回复 分享
发布于 2022-09-01 15:25 广东
我感觉这题不可以用二分法,可以举很多反例呀,我认为可以通过排序找到最大值,再在原数组中找到最大值的索引即可,时间复杂度也是nlogn了
点赞 回复 分享
发布于 2022-09-04 09:38 安徽
[1,2,1,2,3,4]是不对的 按照题解的二分解决是错误的的
点赞 回复 分享
发布于 2022-09-06 16:18 黑龙江
本来想学习一下二分法,为什么C++的代码 我直接拷贝过来 过不了测试结果?
点赞 回复 分享
发布于 2022-10-05 10:03 四川
二分选择一侧比自己大保证一定能找到(走到最左最右侧),扔掉小于当前的也可能有(若一直递减就没有)
点赞 回复 分享
发布于 2023-04-17 20:57 江苏
c++代码我直接拷过来都通不过测试,joker
点赞 回复 分享
发布于 2023-05-25 14:27 重庆
如果测试用例是[2,4,1,2,7,8,9],那返回的值是index=6,而不是index=1
点赞 回复 分享
发布于 2023-06-19 09:52 北京
这题解是错的,第一个测试用例都过不了
点赞 回复 分享
发布于 2023-09-06 22:59 北京
官方代码都通过不了????
点赞 回复 分享
发布于 2023-10-17 22:32 安徽
题解错了用例:[2,4,4,2,1,8,4] 返回2 不符合条件4
点赞 回复 分享
发布于 07-09 23:17 江苏

相关推荐

10-07 20:48
门头沟学院 Java
听说改名就会有offer:可能是实习上着班想到后面还要回学校给导师做牛马,看着身边都是21-25的年纪,突然emo了了
点赞 评论 收藏
分享
56 28 评论
分享
牛客网
牛客企业服务