Find Peak Element
给定一个序列,找到一个位置i满足 nums[i]>nums[i−1]&&nums[i]>nums[i+1] ,其中 nums[−1] 和 nums[n] 可以看成负无穷。要求时间复杂度是O(logN)
本题实际上是局部最大值的问题,如果从头遍历到尾寻找第一个满足条件的位置i,那么一定有下面两个条件
- nums[0 : i]是递增的
- nums[i+1]<nums[i]
所以如果是顺序遍历的话只需要找到第一个满足条件二的位置即可,因为满足条件二就间接使得条件一成立
代码如下,复杂度为O(N)
class Solution {
public:
int findPeakElement(vector<int>& nums) {
for(int i = 1; i < nums.size(); ++i)
{
if(nums[i] < nums[i - 1])
return i - 1;
}
return nums.size() - 1;
}
};
O(logN)的解法肯定和二分有关,考虑 nums[middle] ,本题不能拿它和 nums[left] 以及 nums[right] 比较,因为约束条件是大于相邻元素,所以把目光放在 nums[middle+1] 上,如果 nums[middle]>nums[middle+1] ,那么右侧满足,可以将范围缩小到 [left:middle] 上,同理如果小于可以将范围缩小到 [middle+1:right] 上
可以这样缩小范围的原因是nums[0]和nums[n-1]已经满足一侧的条件,即nums[0]>nums[-1],nums[n-1]>nums[n],所以如果左边缩小到nums[0],那么0就是目标位置,同理右边n-1是目标位置
代码如下
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int left = 0;
int right = nums.size() - 1;
while(left < right)
{
int middle = left + (right - left) / 2;
if(nums[middle] > nums[middle + 1])
right = middle;
else
left = middle + 1;
}
return left;
}
};
本题主要是弄清楚二分法不一定必须拿nums[middle]和nums[left]和nums[right]比较,当约束条件是相邻元素时,可以和左右两边进行比较。