162. 寻找峰值
难度 中等
峰值元素是指其值严格大于左右相邻值的元素。
给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞ 。
你必须实现时间复杂度为 O(log 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。
提示:
1 <= nums.length <= 1000-231 <= nums[i] <= 231 - 1- 对于所有有效的
i都有nums[i] != nums[i + 1]
题解
这道题挺容易理解的,就是找到极大值,极大值点可能有多个返回,只要返回一个就行了。如果在数学中,我们可以直接求导,判断导数为不为零来进行求解。但是我们这里没有函数,只有一个数组,那我们如果求解呢。可以直接暴力,从头开始遍历,遍历到一个从上升到下降转折点就是我们的极大值点了,不过我们不讨论这种方法,不满足题目O(log n)的要求。
要满足O(log n)的时间复杂度,那么我们只能往二分这边想了。假设我们进行二分查找,如果你带入数组想一想就会有以下四种情况
- mid这个点的值大于左右两边的,这样我们直接返回mid
- mid这个点的值大于左边,小于右边,即极大值在右边,这样我们设start = mid +1
- mid这个点的值小于左边,大于右边,即极大值在左边,这样我们设end = mid - 1
- mid这个点的值小于左右两边的,这样极大值可以在左边也可以在右边,这里我为了统一标准,避免二义性,就把极大值放在右边,即设start = mid + 1;
class Solution {
public int findPeakElement(int[] nums) {
int start = 0;//左指针
int end = nums.length - 1;//右指针
int mid = 0;
while(start <= end){
mid = start + (end - start) / 2;//防止溢出
boolean flag1 = false;//大于左边标志
boolean flag2 = false;//大于右边标志
if(mid - 1 >= 0 && nums[mid] > nums[mid - 1]){//数组边界处理和判定是否大于左边
flag1 = true;
}
if(mid + 1 <= nums.length - 1 && nums[mid] > nums[mid + 1]){//数组边界处理和判定是否大于右边
flag2 = true;
}
if(flag1 && flag2){//大于左右,极大值
break;
}else if(flag1 && !flag2){//大于左,小于右,极大值在右边,往右走
start = mid + 1;
}else if(!flag1 && flag2){//小于左,大于右,极大值在左边,往左走
end = mid - 1;
}else{//小于左右,统一标准,往右走
start = mid + 1;
}
}
return mid;
}
}