1.题目解析
题目来源:852.山脉数组的峰顶索引
测试用例
题目来源:162.寻找峰值
测试用例
2.算法原理
山脉数组的峰顶索引
根据二段性将山脉数组分为两段:上升段与下降段
1.当mid指针落入上升段,说明峰值在mid指针后,要从左边缩小范围,此时将mid给left
2.当mid指针落入下降段,说明峰值在mid指针前,需要从右边缩小范围,此时将mid-1给right即可
注意:由于在处理mid指针时出现了mid-1,则在初始化mid时需要使用left+(right-left+1)/2,而不是left+(right-left)/2,如果是mid+1则是第二种
寻找峰值
与前一道题相同但是多了一个条件:nums[0] = nums[n-1] = 负无穷
根据二段性将数组分为两段:上升段与下降段
1.当mid指针落入上升段,说明峰值在mid指针后,要从左边缩小范围,此时将mid给left
2.当mid指针落入下降段,说明峰值在mid指针前,需要从右边缩小范围,此时将mid-1给right即可
注意:由于在处理mid指针时出现了mid-1,则在初始化mid时需要使用left+(right-left+1)/2,而不是left+(right-left)/2,如果是mid+1则是第二种
为什么可以直接确定峰值的位置在mid的那个位置呢?
因为由于山脚都是负无穷,如果mid在上升段那么即便数组一直处于上升那么最后一个元素也是峰值,相应的在下降段即便数组整体都是降序,那么第一个元素也是峰值,与其纠结上升段前可能会有峰值不如选择上升段后一定有峰值,下降段也是如此,大概可以理解为贪心
3.实战代码
山脉数组的峰顶索引
class Solution {
public:
int peakIndexInMountainArray(vector<int>& arr)
{
int left = 1,right = arr.size() - 2;
while(left < right)
{
int mid = left + (right - left + 1) / 2;
//mid指针落入上升段,将左指针指向mid
//从左边缩小范围
if(arr[mid] >= arr[mid - 1])
{
left = mid;
}
//mid指针落入下降段,将右指针指向mid指针的前一个
//从右边缩小范围
else
{
right = mid - 1;
}
}
return left;
}
};
寻找峰值
class Solution {
public:
int findPeakElement(vector<int>& nums)
{
int left = 0,right = nums.size() - 1;
while(left < right)
{
int mid = left + (right - left) / 2;
//处于上升段,峰值在mid指针之后
//从左边缩小范围
if(nums[mid] < nums[mid + 1])
{
left = mid + 1;
}
//处于下降段,峰值在mid指针之前
//从右边缩小范围
else
{
right = mid;
}
}
return left;
}
};