【LeetCode】162. 寻找峰值

leetcode

 

解题思路

寻找峰值问题要求在时间复杂度 O(log n) 内找到数组中任意一个严格大于左右相邻值的元素索引。核心思路是利用​​二分查找的爬坡法​​:

  1. ​​边界假设​​:数组首尾的虚拟元素为负无穷(nums[-1] = nums[n] = -∞),保证数组两端也可能是峰值。
  2. ​​爬坡原理​​:比较中点元素与右侧元素:
    • 若 nums[mid] > nums[mid+1],说明左侧存在峰值(含 mid)
    • 若 nums[mid] < nums[mid+1],说明右侧存在峰值(不含 mid)
  3. ​​终止条件​​:当 left == right 时,当前位置即为峰值。

关键步骤

  1. ​​初始化指针​​:
    • left = 0right = len(nums)-1
  2. ​​二分循环​​(left < right):
    • 计算中点 mid = left + (right - left)/2(防溢出)
    • ​​右侧爬坡​​:若 nums[mid] < nums[mid+1],则 left = mid + 1
    • ​​左侧爬坡​​:若 nums[mid] > nums[mid+1],则 right = mid
  3. ​​返回结果​​:循环结束时 left 即为峰值索引。

​​为何不比较左侧?​​
因相邻元素不相等(nums[i] ≠ nums[i+1]),只需比较右侧即可判断趋势方向。


代码实现

func findPeakElement(nums []int) int {
    left, right := 0, len(nums)-1
    for left < right {
        mid := left + (right-left)/2 // 防溢出计算中点
        if nums[mid] < nums[mid+1] {
            left = mid + 1 // 右侧爬坡
        } else {
            right = mid // 左侧爬坡
        }
    }

    return left // left == right 时为峰值位置
}
 

代码解析

  1. ​​循环条件​​:left < right 确保指针相遇时终止(此时定位到峰值)。
  2. ​​中点计算​​:left + (right-left)/2 等价于 (left+right)/2 但避免溢出。
  3. ​​爬坡逻辑​​:
    • nums[mid] < nums[mid+1] → 右侧更高 → 向右移动
    • nums[mid] > nums[mid+1] → 左侧更高 → 向左移动(保留 mid 因它可能是峰值)

示例测试

func main() {
    // 示例1:峰值在中间
    nums1 := []int{1, 2, 3, 1}
    fmt.Println(findPeakElement(nums1)) // 输出: 2 (nums[2]=3是峰值)

    // 示例2:多个峰值(返回任意一个)
    nums2 := []int{1, 2, 1, 3, 5, 6, 4}
    fmt.Println(findPeakElement(nums2)) // 可能输出: 1 (nums[1]=2) 或 5 (nums[5]=6)

    // 边界测试:峰值在首尾
    nums3 := []int{5, 4, 3, 2, 1}       // 峰值在开头 (nums[0]=5 > nums[1])
    fmt.Println(findPeakElement(nums3)) // 输出: 0

    nums4 := []int{1, 2, 3, 4, 5}       // 峰值在结尾 (nums[4]=5 > nums[3])
    fmt.Println(findPeakElement(nums4)) // 输出: 4
}

复杂度分析

​​指标​​​​值​​​​说明​​
​​时间复杂度​​ O(log n) 每次循环范围减半,最坏 log n 次比较
​​空间复杂度​​ O(1) 仅用常数级变量存储指针

关键点总结

    1. ​​爬坡法本质​​:
      通过比较中点与右侧元素,始终向更高方向移动,最终收敛到峰值。
    2. ​​边界处理​​:
      • 数组首尾的负无穷假设确保算法普适性
      • 相邻元素不等保证比较有效性
    3. ​​二分细节​​:
      • ​​right = mid 而非 mid-1​​:因 mid 可能是峰值(如 [5,1] 中 mid=0
      • ​​left = mid + 1​​:因 mid 比右侧小,不可能是峰值
    4. ​​多峰值处理​​:
      算法优先返回最先遇到的峰值,无需遍历所有可能解。
posted @ 2025-06-19 12:05  云隙之间  阅读(35)  评论(0)    收藏  举报