162. 寻找峰值
题目
峰值元素是指其值大于左右相邻值的元素。
给定一个输入数组 nums
,其中 nums[i] ≠ nums[i+1]
,找到峰值元素并返回其索引。
数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞
。
示例 1
:
输入: nums = [1,2,3,1]
输出: 2
解释: 3
是峰值元素,你的函数应该返回其索引 2
。
示例 2
:
输入: nums = [1,2,1,3,5,6,4]
输出:1
或 5
解释: 你的函数可以返回索引 1
,其峰值元素为 2
;
或者返回索引 5
, 其峰值元素为 6
。
说明:
你的解法应该是 O(logN)
时间复杂度的。
在真实的面试中遇到过这道题?
思路
注意,这里要求解法的复杂度为:O(logN)
,我们第一直接想到的是二分查找,但是这里的数组元素不是有序的,如果使用二分查找,就不能依据有序性来决定跳转策略,所以这里需要我们分析数组的特点,来制定二分查找的跳转策略,可以根据反证法进行证明这种跳转策略的合理性。
关键点:改造传统的二分查找过程,不是根据数组的有序性而是根据数组和题目的特点来决定跳转策略
代码
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int n = nums.size();
if(n == 0)
return -1;
int l = 0;
int r = n-1;
//在给定范围内寻找一定存在的满足条件的值,左右端点也是查找的对象
//所以这里的循环条件使用<=
wrile(l <= r)
{ //4->1或者2,
//3->1
//直白的写出来,使跳转更容易理解,程序也更加的直白
//不要使用过于隐晦的技巧
if(r-l == 0)
return l;
if(r-l == 1)
return (nums[l] > nums[r])?l:r;
int mid = l+(r-l)/2;
//这里的查找方向跳转可以使用反证法证明
if(nums[mid-1] > nums[mid])
r = mid-1;//往更高的点的方向转进
else if(nums[mid+1] > nums[mid])
l = mid+1;//往更高的点的方向转进
else
return mid;
}
return -1;
}
};