[题解]LeetCode 162. 寻找峰值 (C++)

题目

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。

你可以假设 nums[-1] = nums[n] = -∞ 。

你必须实现时间复杂度为 O(log n) 的算法来解决此问题。

示例 1:

输入:nums = [1,2,3,1]
输出:2
解释:3 是峰值元素,你的函数应该返回其索引 2

示例 2:

输入:nums = [1,2,1,3,5,6,4]
输出:15 
解释:你的函数可以返回索引 1,其峰值元素为 2;
     或者返回索引 5, 其峰值元素为 6

提示:

  • 1 <= nums.length <= 1000
  • \(-2^{31} <= nums[i] <= 2^{31} - 1\)
  • 对于所有有效的 i 都有 nums[i] != nums[i + 1]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-peak-element
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

题中明确要求实现时间复杂度O(log(n))的算法,同时给出了所有元素都和其相邻元素不同的保证,显然是要用二分查找。我们要找到峰值元素,也就是说要找到一个比其左右两侧的元素都要大的元素,注意nums[0]和nums[n - 1]默认满足比-1位置和n位置的大。那么,对于nums[0]和nums[n-1]特殊考虑,只要满足大于另一侧的就行了;而对于处在其余位置的,需要判断其是否是峰值元素,如果不是,判断是在下降序列还是上升序列,根据情况修改二分查找的左右边界。
时间复杂度O(log(n)),空间复杂度O(1)。

代码

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int n = nums.size();
        int left = 0, right = n - 1;
        while(left < right)
        {
            int mid = (left + right)/2;
            if(mid == 0){
                if(mid == n - 1)
                {
                    return mid;
                }
                else
                {
                    if(nums[mid] > nums[mid + 1]){
                        return mid;
                    }
                    else
                    {
                        left = mid + 1;
                    }
                }
            }
            else if(mid == n - 1){
                if(mid == 0)
                {
                    return mid;
                }
                else{
                    if(nums[mid] > nums[mid - 1]){
                        return mid;
                    }
                    else{
                        right = mid - 1;
                    }
                }
            }
            else{
                if(nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1]){
                    return mid;
                }
                else if(nums[mid] < nums[mid - 1]){
                    right = mid - 1;
                }
                else{
                    left = mid + 1;
                }
            }
        }
        return left;
    }
};

改进

上面的一堆逻辑纯属脱裤子放屁——多此一举,我们需要搞清楚一个问题:什么情况下mid会变成0或者n-1?变成0那必然是left == 0 && (right == 0 || right == 1),这种情况下只需要判断nums[mid]和nums[mid + 1](mid + 1不会越界,看后面)的大小就行了;而mid变成n - 1是不可能发生的,因为此时left和right都必须等于n-1,根本过不了循环判定。同时,由于nums[0] > nums[-1],也就是说数组从一个上升序列开始,我们只要找到第一个满足nums[i] > nums[i + 1]的元素就行了,而且i != n - 1,在循环中甚至不需要判定下标越界。另外注意当我们发现nums[mid] > nums[mid + 1]时,需要把right变为mid,然后进行下一次循环,因为我们不能确定当前的mid就是第一个满足nums[i] > nums[i + 1]的元素,所以还需要进一步的判断。
时间复杂度和空间复杂度不变但是代码复杂度下降了XD

代码

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int n = nums.size();
        int left = 0, right = n - 1;
        while(left < right)
        {
            int mid = (left + right)/2;
            if(nums[mid] < nums[mid + 1]){
                left = mid + 1;
            }
            else{
                right = mid;
            }
        }
        return left;
    }
};
posted @   浮生的刹那  阅读(262)  评论(0编辑  收藏  举报
编辑推荐:
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
点击右上角即可分享
微信分享提示