描述(注:寻找峰值_牛客题霸_牛客网)
给定一个长度为n的数组nums,请你找到峰值并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个所在位置即可。
1.峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于
2.假设 nums[-1] = nums[n] = −∞
3.对于所有有效的 i 都有 nums[i] != nums[i + 1]
4.你可以使用O(logN)的时间复杂度实现此问题吗?
数据范围:
1≤nums.length≤2×10^5
−2^31<=nums[i]<=2^31−1
如输入[2,4,1,2,7,8,4]时,会形成两个山峰,一个是索引为1,峰值为4的山峰,另一个是索引为5,峰值为8的山峰,如下图所示:
面对这个问题时,我认为主要是看清楚题目,并仔细分析要求。
也就是没有相等的相邻数据,当仅有一个值时,那个该值就是峰值。
当n=>2时,峰值可能在最左边,最右边和中间,这三个地方。
下面写出代码:
class Solution:
def findPeakElement(self , nums: List[int]) -> int:
# write code here
n=len(nums)
if(n==1 or (nums[0]>nums[1])):
return 0
if(nums[n-1]>nums[n-2]):
return n-1
min,max=1,len(nums)-1
while(min<max):
mid=int((min+max)/2)
if(nums[mid]>nums[mid-1] and (nums[mid]>nums[mid+1])):
return mid
if(nums[mid]<nums[mid-1]):
max=mid
if(nums[mid]<nums[mid+1]):
min=mid
return -1
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* @param nums int整型一维数组
* @return int整型
*/
public int findPeakElement (int[] nums) {
// write code here
int n=nums.length;
if(n==1 || nums[0]>nums[1]){
return 0;
}
if(nums[n-1]>nums[n-2]){
return n-1;
}
int min=1;
int max=n-1;
while(min<max){
int mid=(min+max)/2;
if(nums[mid]>nums[mid-1]&&nums[mid]>nums[mid+1]){
return mid;
}
if(nums[mid]<nums[mid-1]){
max=mid;
}
if(nums[mid]<nums[mid+1]){
min=mid;
}
}
return -1;
}
}
代码中前面两个if函数表示,我什么都不看,先看两段,能不能成为峰值,因为这两个端点只需要比较一次就可以出结果了。
把特别的要素排除:
n==1,表示仅有一个值。
第一个最左边端点:也就是索引为0,和索引为1比较。
第二个最右边端点:也就是索引为n-1,和索引为n-2比较。
如果以上都不是,那么只能在中间。
这里应用了二分类的方法,但是不同的地方在于判别语句中,不是target目标值和数相等,而是取mid的两边的数比较都小于mid,那就是我想要的结果mid。
这里依旧难点在于mid,min,max的取值。它们如何取,理念可以看二分类方法。
注:这里特别强调max和min的取值截断一半时,都是mid,不需要加1和减1,以免漏掉了。
个人总结:
对于该题,一定要读懂题目,难度可以小一半。
这里题目说明数组中相邻两个数不相等。那么二分法就很好寻找其中的值,而且时间复杂度也满足。
结果只需要输出一个峰值,不是所有峰值。那么可以一个个判别两段,这样最快的结果。最后再想中间的取值。