【LeetCode】162. 寻找峰值
解题思路
寻找峰值问题要求在时间复杂度 O(log n) 内找到数组中任意一个严格大于左右相邻值的元素索引。核心思路是利用二分查找的爬坡法:
- 边界假设:数组首尾的虚拟元素为负无穷(
nums[-1] = nums[n] = -∞
),保证数组两端也可能是峰值。 - 爬坡原理:比较中点元素与右侧元素:
- 若
nums[mid] > nums[mid+1]
,说明左侧存在峰值(含 mid) - 若
nums[mid] < nums[mid+1]
,说明右侧存在峰值(不含 mid)
- 若
- 终止条件:当
left == right
时,当前位置即为峰值。
关键步骤
- 初始化指针:
left = 0
,right = len(nums)-1
- 二分循环(
left < right
):- 计算中点
mid = left + (right - left)/2
(防溢出) - 右侧爬坡:若
nums[mid] < nums[mid+1]
,则left = mid + 1
- 左侧爬坡:若
nums[mid] > nums[mid+1]
,则right = mid
- 计算中点
- 返回结果:循环结束时
left
即为峰值索引。
为何不比较左侧?
因相邻元素不相等(nums[i] ≠ nums[i+1]
),只需比较右侧即可判断趋势方向。
代码实现
代码解析
- 循环条件:
left < right
确保指针相遇时终止(此时定位到峰值)。 - 中点计算:
left + (right-left)/2
等价于(left+right)/2
但避免溢出。 - 爬坡逻辑:
nums[mid] < nums[mid+1]
→ 右侧更高 → 向右移动nums[mid] > nums[mid+1]
→ 左侧更高 → 向左移动(保留 mid 因它可能是峰值)
示例测试
复杂度分析
指标 | 值 | 说明 |
---|---|---|
时间复杂度 | O(log n) | 每次循环范围减半,最坏 log n 次比较 |
空间复杂度 | O(1) | 仅用常数级变量存储指针 |
关键点总结
- 爬坡法本质:
通过比较中点与右侧元素,始终向更高方向移动,最终收敛到峰值。 - 边界处理:
- 数组首尾的负无穷假设确保算法普适性
- 相邻元素不等保证比较有效性
- 二分细节:
-
right = mid
而非mid-1
:因mid
可能是峰值(如[5,1]
中mid=0
) -
left = mid + 1
:因mid
比右侧小,不可能是峰值
-
- 多峰值处理:
算法优先返回最先遇到的峰值,无需遍历所有可能解。