问题描述:
峰值元素是指其值大于左右相邻值的元素。
给定一个输入数组 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) 时间复杂度的。
基本思路:
原来之前盯了这么久的二分模板2就是这样啊。。。
本质上就是目标位置与周围位置相关——比如在这道题中,我就要把指针指向的元素和周围两个元素相比。
当然这类题目还有一个坑——那就是可能会出现越界的错误。
还是以这道题为例,如果目标元素在数组最前面和最后面,那么之前的结果必然会出现错误。
解决办法是把它当做特殊情况来判断。
还有一点要注意的是我们不是按照该元素的绝对位置来特殊情况判断的,
而是利用区间的大小来进行的。
AC代码:
class Solution {
public:
int FindPeak(vector<int> &a, int l, int r) {
// 终止条件
if (l > r) return -1;
// 特殊情况处理
// 这里处理的特殊情况应该是与当前区间大小有关,而不是和m的绝对位置相关
if (l == r) return l;
if (l == r - 1) return a[l] > a[r]? l : r;
int m = l + (r - l) / 2;
// 常规情况处理
if (a[m] > a[m - 1] && a[m] > a[m + 1]) return m;
if (a[m] < a[m - 1] && a[m] > a[m + 1]) return FindPeak(a, l, m - 1);
if (a[m] > a[m - 1] && a[m] < a[m + 1]) return FindPeak(a, m + 1, r);
return FindPeak(a, l, m - 1) == -1? FindPeak(a, m + 1, r) : FindPeak(a, l, m - 1);
}
int findPeakElement(vector<int>& nums) {
return FindPeak(nums, 0, nums.size() - 1);
}
};