一起刷LeetCode——寻找峰值(二分查找)

61 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第19天,点击查看活动详情

寻找峰值

峰值元素是指其值严格大于左右相邻值的元素。给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。你可以假设 nums[-1] = nums[n] = -∞ 。你必须实现时间复杂度为 O(log n) 的算法来解决此问题。

分析

  • 寻找一个整数数组的峰值,返回索引,并且保证了峰值元素严格大于左右相邻值,翻译一下就是找这个数组的最大值,并且保证了数组相邻元素不相等,最简单易懂的方法就是直接遍历数组

顺序遍历

  • 从数组头部开始,遍历过程中维护已遍历数组的最大值和最大值的索引,直至遍历结束,直接返回最大值的索引就可以得到答案
  • 但是要实现的时间复杂度是O(n),可以在这个基础上做一个优化,因为相邻元素不相等,当前元素的左边元素要么比它大,要么比它小,确定第一个 nums[i] > nums[i+1] 的位置,左边元素只能比当前元素小,所以看右边元素也比当前元素小的位置就是答案,一旦遍历到就结束遍历,所以在某种程度上效率会和O(logn)差不多

代码

var findPeakElement = function(nums) {
    for(let i = 0; i < nums.length; i++) {
        if(nums[i] > nums[i+1]) return i;
    }
    return nums.length-1;
};

二分查找

  • 很多人就会较真,题目要求的是O(logn)的复杂度,弄个O(n)冒充O(logn),总是不好的,看到时间复杂度为O(logn)的查找算法,能比较快速的想到二分查找
  • 使用两个指针指向数组的首尾,当前元素是中间指针指向的元素,如果相邻的右边元素大于当前元素,那向右一定有一个峰值,向右查找,如果相邻的左边元素大于当前元素,那左边一定有一个峰值,向左查找,如果相邻两边的元素都小于当前元素,得到答案

代码

var findPeakElement = function(nums) {
    let left = 0, right = nums.length-1, mid;
    
    while(left < right) {
        mid = Math.floor((right+left)/2);
        if(nums[mid] > nums[mid+1]) right = mid;
        else left = mid+1;
    }
    return left;
};

总结

  • 对于简单方法的优化可能比相对复杂的方法的难度还大,但是因为本题中相邻元素严格不同,所以在优化O(n)方法的时候有神来之笔,如果为了AC,还是用稳妥的方法来解决问题
  • 今天也是有收获的一天