携手创作,共同成长!这是我参与「掘金日新计划 · 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,还是用稳妥的方法来解决问题
- 今天也是有收获的一天