当前位置: 首页 > article >正文

Leetcode力扣秋招刷题路-0852

从0开始的秋招刷题路,记录下所刷每道题的题解,帮助自己回顾总结

852. 山脉数组的峰顶索引

符合下列属性的数组 arr 称为 山脉数组 :
arr.length >= 3
存在 i(0 < i < arr.length - 1)使得:
arr[0] < arr[1] < … arr[i-1] < arr[i]
arr[i] > arr[i+1] > … > arr[arr.length - 1]
给你由整数组成的山脉数组 arr ,返回任何满足 arr[0] < arr[1] < … arr[i - 1] < arr[i] > arr[i + 1] > … > arr[arr.length - 1] 的下标 i 。

示例 1:
输入:arr = [0,1,0]
输出:1

示例 2:
输入:arr = [0,2,1,0]
输出:1

示例 3:
输入:arr = [0,10,5,2]
输出:1

示例 4:
输入:arr = [3,4,5,1]
输出:2

示例 5:
输入:arr = [24,69,100,99,79,78,67,36,26,19]
输出:2

提示:
3 <= arr.length <= 1 0 4 10^4 104
0 <= arr[i] <= 1 0 6 10^6 106
题目数据保证 arr 是一个山脉数组

进阶:很容易想到时间复杂度 O(n) 的解决方案,你可以设计一个 O(log(n)) 的解决方案吗?

解析
题目已经保证所给数组是山脉数组,即前一段单调递增,后一段单调递减,所以我们需要查找的就是数组中最大的那个值,也可以说是极值点

方法一、顺序查找
最简单的办法就是我们一个一个数的由前向后查找,当发现从某一个数开始数值变小了,那就是我们要查找的值了

class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        int n = arr.length - 1;
        for (int i = 1; i < n; ++i) {
            if (arr[i] > arr[i + 1])
                return i;
        }
        return n;
    }
}

时间复杂度: O(n)
空间复杂度: O(1)

方法二、二分查找
题目进阶要求 O(logn) 的时间复杂度,又联系到数组是局部有序的,很容易就能想到要使用二分查找。
因为待查找的是极大值点,所以我们可以根据mid中点的情况来判断极大值的情况

若中点值比右方值大,说明极值点在中点左侧(包括中点)
若中点值比右方小,说明极值点在中点右侧(不包括中点)
概括的说就是,查找第一个 arr的值比下一个位置的arr的值大 的下标,也就是类似lower_bound() 和 bisect_left()

class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        int left = 1, right = arr.length - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (arr[mid] > arr[mid + 1])
                right = mid;
            else
                left = mid + 1;
        }
        return left;
    }
}

时间复杂度: O(logn)
空间复杂度: O(1)

方法三、三分查找
对于查找极值点,也可以采用三分的方法,即用两个点将区间三等分,通过比较两个三等分点可以排除掉左区间或右区间

若左等分点大于右等分点,有两种情况:极大值点在左区间或中区间,所以可以排除右区间
若左等分点小于右等分点,有两种情况:极大值点在中区间或右区间,所以可以排除左区间

class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        int left = 1, right = arr.length - 1;
        while (left < right) {
            int m = (right - left) / 3;
            int m1 = left + m, m2 = right - m;
            if (arr[m1] > arr[m2])
                right = m2 - 1;
            else
                left = m1 + 1;
        }
        return left;
    }
}

时间复杂度: O(logn)
空间复杂度: O(1)

经过三叶姐的指导,下面这个应该说是二分变形的解法,对于标准二分法来说做了一点点常数级别的优化

看起来三分查找每次只能排除 1 3 \dfrac{1}{3} 31,还不如二分查找每次排除 1 2 \dfrac{1}{2} 21

这是因为我们并没有充分利用三分的两个三等分点单调方面的性质,我们考虑如下三种情况:

极大值点在左区间,那么两个三等分点都是单调递减的
极大值点在右区间,那么两个三等分点都是单调递增的
极大值点在中间区间,那么第一个三等分点是单调递增的,第二个三等分点是单调递减的
由此,我们可以得到每次都能排除掉 1 3 \dfrac{1}{3} 31的做法

class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        int left = 1, right = arr.length - 2;
        while (left < right) {
            int m = (right - left) / 3;
            int m1 = left + m, m2 = right - m;
            if (arr[m1] > arr[m1 + 1])
                right = m1;
            else if (arr[m2] < arr[m2 + 1])
                left = m2 + 1;
            else {
                left = m1 + 1;
                right = m2;
            }
        }
        return left;
    }
}

时间复杂度: O(logn)
空间复杂度: O(1)


http://www.kler.cn/a/15517.html

相关文章:

  • Halcon HImage 与 Qt QImage 的相互转换(修订版)
  • Java 动态代理初步
  • ONLYOFFICE8.2版本测评,团队协作的办公软件
  • 3D意识(3D Awareness)浅析
  • 代码版本管理艺术
  • onlyoffice Command service(命令服务)使用示例
  • 优思学院|精益生产为企业带来革命性转变的效益
  • Linux centos重装yum
  • GCM与CCM的的规格和加解密过程
  • 网页爬虫之WebPack模块化解密(JS逆向)
  • 学习笔记-主成分分析法
  • SpringBoot+Vue3实现登录验证码功能
  • CentOS计划任务的用法
  • 学系统集成项目管理工程师(中项)系列13a_人力资源管理(上)
  • Whistle安装与使用
  • javaEE+mysql学生竞赛管理系统
  • 亚马逊广告怎么做?广告效果如何提升?
  • 六级英语历年真题单词--按年份分类--持续更新中...
  • 【Java笔试强训 8】
  • 文件 IO 操作
  • jQuery知识点三
  • Linux命令集(Linux常用命令--cat指令篇)
  • 中级软件设计师备考---信息系统安全
  • 最新国内免费chatgpt 的试用方法
  • 首期smardaten无代码训练营圆满收官,两周内容精彩回顾!
  • 基于opencv的YOLOV3对图片的目标检测