LeetCode 162中等二分查找 · 找峰值
寻找峰值 图解题解
这道题到底在问什么
找出任意一个峰值的下标(峰值 = 比左右邻居都大)。可假设两端之外是负无穷,所以一定存在峰值。
- nums
- [1,2,1,3,5,6,4]
- 输出
- 5(值 6 是峰)
先想最直接的笨办法
挨个检查每个数是不是比左右都大,O(n) 能做。但数组并不需要有序——只要懂「往高处走必有峰」,就能砍到 O(log n)。(动画第 3 步)
最优解:一步一步想明白
- 3挨个检查每个数是不是比左右都大,O(n) 能做。但数组并不需要有序——只要懂「往高处走必有峰」,就能砍到 O(log n)。
- 4转折:数组没排序,凭什么二分?凭「两端是负无穷 → 一定存在峰」这条保证。不变量:始终让搜索区间 [l, r] 里至少包含一个峰。怎么收?拿 nums[mid] 和右邻 nums[mid+1] 比:若 nums[mid] < nums[mid+1],当前在上坡,右边继续走早晚到顶,峰在右(l=mid+1);若 nums[mid] > nums[mid+1],当前在下坡,mid 自己可能就是峰,峰在 mid 或其左(r=mid)。一直往高处走,必撞上峰。
- 5l=0, r=6范围是整个数组,l=0、r=6。每轮都拿 nums[mid] 和它的右邻 nums[mid+1] 比,判断往哪边爬。
- 6mid = (0+6)//2 = 3中点 mid=3,nums[3] = 3。和右邻 nums[4]=5 比,看是上坡还是下坡。
- 73 < nums[mid+1]=5 → 上坡3 < 5,右边更高,说明现在站在上坡上。顺着坡往上走早晚到顶,所以峰一定在 mid 右边,mid 自己不是峰。
- 8l = mid+1 = 4l 跳到 mid+1=4,左半(灰)丢掉。范围缩到 [4, 6],继续往高处爬。
- 9mid = (4+6)//2 = 5范围 [4,6],新中点 mid=5,nums[5] = 6。和右邻 nums[6]=4 比——这轮会走到另一个分支。
- 106 > nums[mid+1]=4 → 下坡6 > 4,右边更低,说明已经翻过峰、在下坡了。那 mid 自己可能就是峰,峰在 mid 或它左边,不能丢 mid。
- 11r = mid = 5r 收到 mid=5(不是 mid−1,因为 mid 自己可能就是峰)。下标 6 丢掉,范围 [4, 5]。
- 12mid = (4+5)//2 = 4范围 [4,5],mid=4,nums[4] = 5。和右邻 nums[5]=6 比。
- 135 < 6 → l = mid+1 = 5,l==r 停5 < 6,又是上坡,峰在右,l 跳到 mid+1=5。现在 l == r == 5,区间只剩一个,循环结束。
- 14l = 5,nums[5] = 6 是峰l 和 r 撞在下标 5,返回 5:nums[5]=6 比左邻 5、右邻 4 都大,确是峰。一路往高处爬,每轮砍一半,O(log n)。
- 17没有 target、数组也不有序,照样能二分——只要存在「单调可判方向」。和右邻比,上坡向右、下坡收左含 mid,是这类「找极值」二分的通用思路。
⚠️ 容易写错的地方
✗ 错:循环写成 while l <= r
✓ 对:while l < r
l==r 时 mid 可能取到末尾,nums[mid+1] 直接越界;用 < 让 l==r 收尾返回 l,从根上避开越界
✗ 错:nums[mid] > nums[mid+1] 时写 r = mid - 1
✓ 对:r = mid(不减 1)
下坡时 mid 自己可能就是峰,减 1 会把峰丢掉
✗ 错:想找「全局最大」才停
✓ 对:找到任意局部峰即可
题目只要任意一个峰,爬坡到的第一个峰就是答案,不必继续找更大的
完整代码(Python)
Python
class Solution:
def findPeakElement(self, nums):
l, r = 0, len(nums) - 1
while l < r:
mid = (l + r) // 2
if nums[mid] < nums[mid + 1]:
l = mid + 1
else:
r = mid
return l套路模板 · 爬坡二分(背下来)
l, r = 0, len(nums) - 1
while l < r:
mid = l + (r - l) // 2
if nums[mid] < nums[mid + 1]:
l = mid + 1 # 上坡,峰在右
else:
r = mid # 下坡,峰在 mid 或其左
return l复杂度
时间复杂度
O(log n)
每轮把区间砍掉一半
空间复杂度
O(1)
只用 l、r、mid 三个变量
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 寻找峰值 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
这道题为什么用「找峰值」,换最直接的暴力解会差在哪?+
找峰值抓住了本题的结构特征,把暴力解里重复的工作省掉;暴力解通常要多嵌套一层枚举,数据一大就超时。具体对比见上文「暴力解及其卡点」与「最优解逐步推演」两节。
时间复杂度为什么是 undefined?怎么推出来的?+
按上文复杂度小节的推导,时间复杂度为 undefined。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。