图解题库 / 二分查找 · 找峰值

162. 寻找峰值

中等 含交互动画

学完这道你应该能: 说清它为什么用「找峰值」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

题目描述

找出任意一个峰值的下标(峰值 = 比左右邻居都大)。可以假设两端之外是负无穷,所以一定存在峰值。

nums = [1,2,1,3,5,6,4]
输出 = 5(值 6 是峰)

思路解析

扫一遍当然行,可数组明明不需要有序也能二分,O(n) 就显得太老实了。

如果 mid 比右邻居小,说明右边在「上坡」,那个方向尽头是负无穷,半路一定有个峰——往右走准没错;反过来往左走。

每次砍掉「肯定下坡」的那半,留住「上坡」的那半,收到只剩一个,它就是峰。

l=0, r=6:mid=3 是 3,右邻居 5 更大,右边在上坡,峰在右边,l 跳到 4。

l=4, r=6:mid=5 是 6,右邻居 4 更小,右边在下坡,峰在左边或就是 mid 自己,r 收到 5。

l=4, r=5:mid=4 是 5,右邻居 6 更大,还在上坡,l 收到 5。现在 l 和 r 都是 5。

l=5, r=5:l 和 r 撞一起,下标 5 的 6 就是峰值。没排序也照样 O(log n) 找到。

记一句话:mid 比右邻居小就往右、否则往左,收到 l==r。因为上坡的尽头被负无穷托着,一定能撞出一个峰。

参考代码(Python)

Python
1def findPeakElement(nums):
2    l, r = 0, len(nums) - 1
3    while l < r:
4        mid = (l + r) // 2
5        if nums[mid] < nums[mid + 1]:  # 右边上坡
6            l = mid + 1                # 峰在右
7        else:                          # 右边下坡
8            r = mid                    # 峰在左(含 mid)
9    return l

复杂度分析

  • 时间复杂度:O(log n) —— 每轮砍一半
  • 空间复杂度:O(1) —— 俩指针

套路模板

骨架四行。判断只看 mid 和 mid+1 谁高,不用管 mid-1——这是它跟普通二分最不一样的地方。

Python
1l, r = 0, n - 1
2while l < r:
3    mid = (l + r) // 2
4    if nums[mid] < nums[mid+1]: l = mid + 1
5    else: r = mid
6return l

易错点

  • 拿 mid 和 mid-1 比 → ✅ 拿 mid 和 mid+1 比(区间用 r=mid 收缩,配 mid+1 才不会越界,方向也才统一)
  • 上坡时 r=mid,下坡时 l=mid+1(搞反) → ✅ 上坡 l=mid+1、下坡 r=mid(上坡说明峰在右、要丢左边;下坡说明峰在左、要丢右边)
  • while l <= r → ✅ while l < r(收敛找位置,l<=r 配 r=mid 会死循环)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →215. 数组中第 K 个最大元素 ← 返回题库