leetcode162. 寻找峰值

断了今生、忘了曾经 提交于 2019-12-04 17:35:26

给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。

数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。

你可以假设 nums[-1] = nums[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。

说明:

你的解法应该是 O(logN) 时间复杂度的。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-peak-element
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解答

写在前面注意这道题的条件是nums[-1] = nums[n] = -∞ ,也就是说,左右两边是最小值,那么只要数组中有个值就肯定会有峰值,毕竟如果画个图像的话,肯定会出现那个转折点,高数忘得差不多了,应该是斜线为0,一次函数中的k。

解法1:可以直接遍历,因为左右两边都是最小值,所以第一个元素就是递增,那么只要有一个减小的元素,说明就出现了峰值。

 1 class Solution {
 2     public int findPeakElement(int[] nums) {
 3         for(int i=0;i<nums.length-1;i++)
 4         {
 5             if(nums[i]>nums[i+1])
 6                 return i;
 7         }
 8         return nums.length-1;
 9     }
10 }
View Code

 

也可以从两边同时开始,但是复杂度都是一样的,都是On,这又说明了,在一个(0~n)的循环中,如果你缩短循环次数,但是你每次循环要做的个数变成2倍的话,还是一样的,说明一次做多个但是只要是你都做了,就是并不会降低复杂度,只有某些元素直接跳过,这样才会降低复杂度。

 1 class Solution {
 2     public int findPeakElement(int[] nums) {
 3      
 4         for(int i=0;i<nums.length-1;i++)
 5         {
 6             if(nums[i]>nums[i+1])
 7                 return i;
 8             if(nums[nums.length-1-i]>nums[nums.length-2-i])
 9                 return nums.length-1-i;
10         }
11         return nums.length-1;
12     }
13 }
View Code

解法2:利用二分法,有关二分法的变种实在太多,每次都会又新的发现,你以为掌握的,其实实在是太少,

1.纯正的二分查找是利用数组有序而将双指针逼近查找有没有命中target,这是最初学习的,我一般喜欢在while循环里面判断条件

while(l<=r) 但是这样写要非常注意最后的结果究竟是l还是r,因为最后跳出循环的时候l,r是不相同的,所以这里要注意。

2.l,r,mid的关系,这三个的关系十分烦人且难搞,究竟l=mid+1,还是l=mid,还是说r=mid-1,r=mid,这都是需要考虑的,尤其是循环判断条件的l是不是包括等于r的情况,不然很有可能是跳不出循环的,一般来说l==r 是要配合mid+1,mid-1使用的,不然可能会出现l==r,然后一直死在这里,

一般l<r,应该是可以用mid+1,mid的,也即是可以不用强迫每一步都跳过边界。

这里提供两种的二分。

 1 class Solution {
 2     public int findPeakElement(int[] nums) {
 3         int l=0;
 4         int r=nums.length-1;
 5         while(l<r)
 6         {
 7             int mid=l+(r-l)/2;
 8             if(nums[mid]<nums[mid+1])
 9                 l=mid+1;
10             else 
11                 r=mid;
12         }
13         return l;
14     }
15 }
View Code
 1 class Solution {
 2     public int findPeakElement(int[] nums) {
 3         int l=0;
 4         int r=nums.length-1;
 5         while(l<=r)
 6         {
 7             int mid=l+(r-l)/2;
 8             if(mid<r&&nums[mid]<nums[mid+1])
 9                 l=mid+1;
10             else if(mid>l&&nums[mid]<nums[mid-1])
11                 r=mid-1;
12             else
13                 return mid;
14         }
15         return l;
16     }
17 }
View Code

总之,二分的条件还是比较多的,需要自己小心,要不要加等号,要不要+1,-1都是需要考虑的,还是需要根据题目的意思来吧,这道题主要是往中间夹。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!