力扣第162题:寻找峰值(二分查找)

一、题目内容

        

 

二、题目分析

        这道题目其实起码有三种做法,第一种就是最简单的遍历,挨个和左右对比,直到找到峰值元素返回下标即可。但是这种方法运气好的话时间复杂度不过O(1),运气差的话,确是O(N),不过确实是一种容易想到的方法。

        

    public int findPeakElement(int[] nums) {
        if(nums.length==1)
            return 0;
        if(nums[0]>nums[1])
            return 0;
        if(nums[nums.length-1]>nums[nums.length-2])
            return nums.length-1;
        for(int i=1;i<nums.length-1;i++)
        {
            if(nums[i]>nums[i-1]&&nums[i]>nums[i+1])
                return i;
        }
        return -1;
    }

        讲道理,这么做真的爽,但是确实没有什么意义。

        第二种方法,就是寻找数组最大值,因为只要找到最大值,那么最大值肯定是峰值

        但是因为这个数组时无序数组,而且没有规律,所以不能使用时间复杂度为O(logn)的二分,只能老老实实找,时间复杂度还是O(n)

        

public int findPeakElement(int[] nums) {
        int max=nums[0];
        int max_index=0;
        int i;
        for(i=0;i<nums.length;i++){
            if(nums[i]>max){
                max=nums[i];
                max_index=i;
            }
        }
        return max_index;
    }

        代码量非常的少,不过也不提倡。

        接下来使我们要重点讲的第三种方法,迭代爬坡

        首先,按照二分查找的老套路,我们定义了left=0,right=nums.length-1.然后我们依然取mid等于中间位置,然后不一样的地方来了。我们比较mid左右两边。

       nums[mid-1] < nums[mid] > nums[mid+1]时,return mid

       nums[mid-1] < nums[mid] < nums[mid+1]时,舍弃左边,left = mid+1

       nums[mid-1] > nums[mid] > nums[mid+1]时,舍弃右边,right = mid-1

       nums[mid-1] > nums[mid] < nums[mid+1]时,随便舍弃一边即可

        上面的原理是什么,首先,如果mid小于右边大于左边,mid右边肯定有符合条件的数!你想,如果从mid开始向右一直递增,那么最后一个数肯定是峰值,如果不是一直递增,而是先递增后递减,那么那个转折的极值点就是峰值!那如果一直递减呢?呵,不可能啊,因为mid+1已经比mid大了,所以这就是原理。

        但是上面的做法只是基于本题而言,因为题目说了nums[i]!=nums[i+1]并且当有多个峰值的时候,任意返回一个即可,要是返回下标最小的峰值就没那么简单了

        

 public int findPeakElement(int[] nums) {
        if(nums.length==1)
            return 0;
        int left = 0, right = nums.length-1;
        while(left <= right){
            int mid = (left+right)/2;
            if(mid==0)
                if(mid+1<nums.length&&nums[mid]>nums[mid+1])
                    return mid;
            if(mid==nums.length-1)
                if(mid-1>=0&&nums[mid]>nums[mid-1])
                    return mid;
            if(mid-1>=0&&mid+1<nums.length&&nums[mid]>nums[mid-1]&&nums[mid]>nums[mid+1])
                return mid;
            if(nums[mid]<nums[mid+1]){
                left=mid+1;
            }
            else if(nums[mid]<nums[mid-1])
            {
                right=mid-1;
            }
        }
        return 0;
       
    }

        略微化简后(代码量):

        

public int findPeakElement(int[] nums) {
        int l = 0, r = nums.length - 1;
        while (l < r) {
            int mid = l + ((r - l) >> 1);
            if (nums[mid] < nums[mid+1]) {
                l = mid + 1;
            } else {
                r = mid;
            }
        }
        return l;
    }

三、后记

        还是决定系统的刷题比较好,今天结束了二分查找部分,明天应该开始双指针。这类题以前也做过不少,大多可以和滑动窗口结合,应该有多解情况。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少๑渊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值