162. 寻找峰值

题目描述

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。

你可以假设 nums[-1] = nums[n] = -∞

你必须实现时间复杂度为 O(log n)的算法来解决此问题。

做题情况

  1. 做出来且思路与标答一致
  2. 做出来但思路较为复杂 ☑
  3. 有思路,但时间复杂度较高无法通过
  4. 没有思路

自己的想法:

二分法自己其实已经想到了,但是如何实践,自己进行的并不好。其实这也不仅仅是二分法写代码自己不是很熟练,而且这种求极值的问题自己套用二分法的时候有点顾此失彼。

标答:

就是标准的二分法。因为是求极值,在一维的情况下,直接进行相邻比较,每次缩减一半的区域就可以了。这和二分法确实不同,二分法有一个介入的数,我们每次都和那个数进行比较。二分法是和下一位进行比较。
现在想想,加一其实是没有什么问题的,因为最极端的情况就是最后以恶搞和倒数第二个,这两个的中间值是前者,还是可以进行加一操作。
下面对二分法进行总结一下吧:
维基百科二分法定义如下

在计算机科学中,二分查找算法也称折半搜索算法,对数搜索算法,是一种在有序数组中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。

其实并不是找最大值,但是可以用来找局部最优值。

自己对于二分法确实掌握的很不好,无论是应用场景的熟悉度还是代码的具体编写。其实二分法有具体的模板的,自己只需要记住就好了,也不会很难的。

首先对于while()中的条件,一定是左<右。左和右的起始条件,一定是可以取到的左右值(即0和-1)

循环体中不需要再设置与左右值相关的弹出条件了。

最后返回值是左值。这其实也不绝对,因为最终是两个值相等之后返回的嘛。但是一般来说,因为两个相邻的数相加除以2会回到较小的那个数,所以一般用左值。但这其实相关性也没有很大。

另外是左值和右值向中间变化的时候,只留下我们用的哪一段就可以了,例如:

middle=(begin+end)/2;
if(nums[middle]>nums[middle+1]) end=middle;
else begin=middle+1;

要留下较大的那一部分,对于if中,是middle,对于else中,是middle+1

实际代码

class Solution {
public:
    int findPeakElement(vector<int>& nums) 
    {
        int n=nums.size();
        int begin=0;
        int end=n-1;
        int middle;
        while (begin<end)
        {
            middle=(begin+end)/2;
            if(nums[middle]>nums[middle+1]) end=middle;
            else begin=middle+1;
        }
        return begin;
    }
};

总结

一般来说,总结当前使用二分法的情况:

  1. 对于有序数组
  2. 对于log(n)或者nlog(n)时间复杂度
  3. 对于求极值的情况(就是进行所谓的爬坡)

总的来说还是要提高对于二分法的警惕,不然太被动了。

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值