【题目链接】
162. 寻找峰值
【题目描述】
【题解】
峰值元素定义为严格大于左右相邻值的元素,且题目给定边界条件
n
u
m
s
[
−
1
]
=
n
u
m
s
[
n
]
=
−
∞
nums[-1] = nums[n] = -∞
nums[−1]=nums[n]=−∞。这一条件至关重要:它保证了数组中至少存在一个峰值(即使数组严格递增,最后一个元素因右侧是
−
∞
-∞
−∞成为峰值;严格递减则第一个元素因左侧是
−
∞
-∞
−∞成为峰值)。
由于要求时间复杂度为 O ( l o g n ) O(log n) O(logn),需用二分查找缩小区间。核心逻辑是:通过比较中间位置 m m m和右侧邻居 m + 1 m+1 m+1的值,判断峰值的大致方向:
- 若
n
u
m
s
[
m
]
>
n
u
m
s
[
m
+
1
]
nums[m] > nums[m+1]
nums[m]>nums[m+1]:
说明 m m m处于下坡段(或本身是峰值)。由于左侧边界是 − ∞ -∞ −∞,从 m m m向左必然存在一个峰值(即使左侧一直递减,最左端因左侧是 − ∞ -∞ −∞也会成为峰值)。因此,缩小右边界到 m m m。 - 若
n
u
m
s
[
m
]
<
n
u
m
s
[
m
+
1
]
nums[m] < nums[m+1]
nums[m]<nums[m+1]:
说明 m m m处于上坡段。由于右侧边界是 − ∞ -∞ −∞,从 m + 1 m+1 m+1向右必然存在一个峰值(即使右侧一直递增,最右端因右侧是 − ∞ -∞ −∞也会成为峰值)。因此,缩小左边界到 m + 1 m+1 m+1。
【AC代码】
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int l = 0, r = nums.size() - 1;
while(l < r) {
int mid = l + r >> 1;
if(nums[mid] > nums[mid + 1])
r = mid;
else
l = mid + 1;
}
return l;
}
};
【思考&收获】
二分算法的两类模板需要熟练掌握,但核心关键在于设计合理的
c
h
e
c
k
check
check函数,它直接定义了“如何根据中间位置的特征,判断下一阶段的搜索方向”。由于每道题的场景逻辑不同,真正的破题点永远是 结合问题条件,分析区间的“可二分性”,而非机械套用模板。