题目地址
162. 寻找峰值
题目分析
O ( n ) O(n) O(n)的算法很好想,很简单,再次不多赘述了;但是 O ( log n ) O(\log n) O(logn)的算法就抓破脑袋也写不出来,这就是差距吧。
二分的思路如下:先判断某个位置i上的数是不是峰值(peak),如果不是,再判断i和i+1位置上的数的大小,如果nums[i+1]>nums[i],那么i+1之后一定有峰值(其实i之前也可能有峰值,但是可能存在0到i一直是单调上升的情况),反过来讲如果nums[i]>nums[i+1],那么i之前一定有峰值,反而是i+1之后可能存在单调递减的情况,根据这个原则可以舍弃掉i之前或者i+1之后的区间,使用二分查找优化算法。
题解
具体的见官解。下面是我写的。
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int n = nums.size();
auto get = [&](int i) -> pair<int, int> {
if (i == -1 || i == n) {
return {0, 0};
}
return {1, nums[i]};
};
int p = 0, q = nums.size()-1;
int mid = (p+q)/2;
while(!(get(mid) > get(mid+1) && get(mid) > get(mid-1)))
{
mid = (p+q)/2;
if(get(mid) < get(mid+1))
p = mid + 1;
else
q = mid - 1;
}
return mid;
}
};
总结
这题不仅学了算法,还学了C++的语法知识,总结一下。
解法二代码如下:
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int n = nums.size();
int idx = rand() % n;
// 辅助函数,输入下标 i,返回一个二元组 (0/1, nums[i])
// 方便处理 nums[-1] 以及 nums[n] 的边界情况
auto get = [&](int i) -> pair<int, int> {
if (i == -1 || i == n) {
return {0, 0};
}
return {1, nums[i]};
};
while (!(get(idx - 1) < get(idx) && get(idx) > get(idx + 1))) {
if (get(idx) < get(idx + 1)) {
idx += 1;
}
else {
idx -= 1;
}
}
return idx;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/find-peak-element/solution/xun-zhao-feng-zhi-by-leetcode-solution-96sj/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
其中有两个知识点:
-
get函数的用法。是一个lambda表达式,基本形式是“[捕获变量] (参数表) {函数体}”,具体见[1]。(其实我没怎么看懂,发现自己对于C++其实一无所知)
-
pair类比较大小,先按照.first比较,如果.first相等,再按照.second比较。