二分查找(山脉数组的峰顶索引)(5)

https://blog.csdn.net/2601_95366422/article/details/158770218

上节课链接

一.题目

852. 山脉数组的峰顶索引 - 力扣(LeetCode)

二.思考讲解

第一步:查找二分性

观察题目描述,数组先递增到一个峰值元素 ,然后递减。这种"先升后降"的单峰特性意味着:在峰值左侧,元素满足 arr[i] < arr[i+1](上升趋势);在峰值右侧,元素满足 arr[i] > arr[i+1](下降趋势)。因此,如果我们取任意一个位置 mid,比较它和它右边的元素 arr[mid+1],就可以判断当前位于峰值的哪一侧:

  • 如果 arr[mid] < arr[mid+1],说明 mid 处于上升段 ,峰值一定在 mid 的右边。

  • 如果 arr[mid] > arr[mid+1],说明 mid 处于下降段 或正好是峰值,峰值在 mid 的左边或就是 mid 本身。 这种"一侧上升一侧下降"的规律,使得我们可以通过比较相邻元素来不断缩小搜索范围,因此数组具备二分性,可以采用二分查找求解。

第二步:采用左端点还是右端点

我们要找的是峰值元素 ,即第一个满足 arr[i] > arr[i+1] 的位置 i(因为一旦进入下降段,第一个下降点就是峰顶)。这是一个典型的寻找第一个满足某条件的位置 问题,因此应该采用左端点二分查找 。用现实中的山来比喻:站在山脚往上看,最先看到的山顶就是第一个出现的最高点,后面即使有更高的山也被遮挡,所以我们要找的是最左边的峰值 。采用左端点模板,中点取向下取整,缩进规则为:

  • arr[mid] < arr[mid+1] 时,说明 mid 还在上升段,峰值在右边,因此 left = mid + 1(舍弃左半区间)。

  • arr[mid] > arr[mid+1] 时,说明 mid 在下降段或就是峰值,峰值在左边或就是 mid,因此 right = mid(保留 mid 继续搜索)。 循环结束时,left 指向的就是第一个下降点,即峰顶索引。

三.代码演示

cpp 复制代码
class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr) 
    {
        int left = 0;
        int right = arr.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left)/2;
            if(arr[mid] < arr[mid + 1])
            {
                left = mid + 1;
            }
            else
                right = mid;
        }
        return left;
    }
};

四.代码讲解

一、循环条件与中点计算

采用 while (left < right) 作为循环条件,而不是 left <= right。这是因为当左右指针相遇时,区间内只剩一个元素,此时无需继续二分 ,可以直接在循环外返回该元素。这种写法可以避免死循环,并符合左端点模板的常规写法。

中点计算采用向下取整 的公式,即 mid = left + (right - left) / 2。当区间长度为偶数时,中点会偏向左边 ,这确保了当 leftright 相邻时,中点指向 left,从而保证区间能够正确收缩,不会出现 right 原地不动的情况。向下取整 是左端点查找的精髓,也是避免死循环的关键。

二、区间缩进规则

在循环中,根据 arr[mid]arr[mid + 1] 的比较结果,按照以下规则更新指针:

  • arr[mid] < arr[mid + 1] :说明 mid 处于上升段 ,峰值一定在 mid 的右侧。因为 mid 本身不可能是峰值(它小于右边),所以可以安全地将左指针移动到 mid + 1,即舍弃左半区间

  • arr[mid] > arr[mid + 1] :说明 mid 处于下降段 或正好是峰值。此时峰值可能在 mid 左侧,也可能就是 mid 本身。因此将右指针移动到 mid保留 mid 在搜索区间内 ,继续向左寻找。注意这里不能用 right = mid - 1 ,因为 mid 有可能是峰值,必须保留。

三、循环结束后的处理

循环结束时,leftright 相等,此时指向的位置就是第一个满足 arr[i] > arr[i+1] 的位置 ,即峰顶索引。直接返回 left 即可,无需额外判断,因为题目保证数组至少有三个元素且存在峰值。

四、细节注意

  • 循环中比较的是 arr[mid]arr[mid+1],因此需要保证 mid+1 不越界。由于循环条件 left < rightright 初始为 size-1,在循环过程中 mid 最大为 right-1(因为向下取整,当 leftright 相邻时,mid = left,此时 mid+1 = right 合法),所以不会越界。

  • 初始 left = 0right = arr.size() - 1,这覆盖了整个数组。

相关推荐
vibecoding日记1 小时前
双非如何快速入职字节等大厂大模型?真实案例分析:推理优化和投机解码
算法·求职·大模型工程师
yszaygr21384 小时前
Verilog参数化游程编码RLE模块
算法
望易4 小时前
刚设计的大模型架构-双域耦合认知框架
算法·架构
复杂网络8 小时前
多个 Claude Code 与多个 Codex 协同工作:设计与实现方案
算法
apocelipes1 天前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
HjhIron1 天前
面试常客:字符串算法从入门到进阶
算法·面试
吴佳浩1 天前
DeepSeek DSpark:Confidence-Scheduled Speculative Decoding 技术解析
人工智能·算法·deepseek
触底反弹1 天前
🧠 搞懂 Token,才算真正入门大模型——从分词原理到 Embedding 语义实战
javascript·人工智能·算法
vivo互联网技术1 天前
ICLR 2026 | 基于后验采样的图像恢复方法LearnIR:人脸去阴影、去雾
人工智能·算法·aigc
浮生望1 天前
JS字符串与回文算法:从包装类到双指针的面试进阶之路
javascript·算法