数据结构与算法之数组寻找峰值&&分而治之

简介: 数据结构与算法之数组寻找峰值&&分而治之

084b7b3457baa8194056d4ccda35e437.png


这一篇分享一道在数组中寻找峰值的题目,使用到分而治之,二分查找等思想。本文章会讲解这个二分查找的本质,以及为什么要用二分查找,它能解决哪一类题目?


一.题目及其要求


1.给定一个长度为n的数组,返回其中任何一个峰值的索引

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

3.数组两个边界可以看成是最小, nums[−1]= nums[ n]=−∞

4.峰值不存在平的情况,即相邻元素不会相等

5.峰值从第二个数开始,不考虑边界的-∞


如输入[2,4,1,2,7,8,4]时,会形成两个山峰,一个是索引为1,峰值为4的山峰,另一个是索引为5,峰值为8的山峰,如下图所示:


b932b7f376b8c80b918c1785b4d55d24.png

示例:

输入:[2,4,1,2,7,8,4] 返回值:1 说明:4和8都是峰值元素,返回4的索引1或者8的索引5都可以 输入:[1,2,3,1] 返回值:2 说明:3 是峰值元素,返回其索引 2


1.分而治之


分治即“分而治之”,意思就是把一个复杂大问题分成若干个简单的小问题,当小问题解决后,大问题也就迎刃而解。“分”指的是将一个大而复杂的问题划分成多个性质相同但是规模更小的子问题,子题继续按照这样划分,直到问题可以被轻易解决;“治”指的是将子问题单独进行处理。经过分治后的子问题,将若干个子问题进行合并才能得到原问题的解,因此整个分治过程经常用递归来实现。


2.题目思路


因为题目只需要找到其中一个波峰,因此不断地往高处走,一定会有波峰。那我们可以每次找一个标杆元素,将数组分成两个区间,每次就较高的一边走,因此也可以用分治来解决,而标杆元素可以选择区间中点。


//右边是往下,不一定有坡峰
if(nums[mid] > nums[mid + 1])
    right = mid;
//右边是往上,一定能找到波峰
else
    left = mid + 1;

下面配图进行理解上面代码:


5308d5ce77da30d7f5e7446c66f136f4.png


3.具体做法+配图演示


  1. 1:二分查找首先从数组首尾开始,每次取中间值,直到首尾相遇。
  2. 2:如果中间值的元素大于它右边的元素,说明往右是向下,我们不一定会遇到波峰,但是那就往左收缩区间。
  3. 3:如果中间值大于右边的元素,说明此时往右是向上,向上一定能有波峰,那我们往右收缩区间。
  4. 4:最后区间收尾相遇的点一定就是波峰。


下面是配图演示:

7755acdf53a8ae7cee349fedd4d3b429.png


72dc3df3b41fb1ef27fc193d54aee80f.png


1984ab7981eb93a85b8c3d3d6f3466b7.png


45c95038cb1df161a9f24c48ef7397a5.png


image.png


image.png


image.png


4.代码实现


class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int left = 0;
        int right = nums.size() - 1;
        //二分法
        while(left < right){ 
            int mid = (left + right) / 2;
            //右边是往下,不一定有坡峰
            if(nums[mid] > nums[mid + 1])
                right = mid;
            //右边是往上,一定能找到波峰
            else
                left = mid + 1;
        }
        //其中一个波峰
        return right; 
    }
};


4.复杂度分析


  • 时间复杂度:O(log2n),二分法最坏情况对整个数组连续二分,最多能分log2n次。
  • 空间复杂度:O(1),常数级变量,无额外辅助空间。


二.剖析二分查找

1.本质

二分查找的本质是二段性,二分查找的过程本质是对可行区间的压缩。只要满足二段性的问题都可以用二分查找解决。

2.优点

通过对有序数组进行逐步缩小范围的操作,将查找时间从线性时间降低到了对数时间,因此它是一种非常高效的搜索算法。

3.适用场景

二分查找的时间复杂度为O(log n),比其他搜索算法的复杂度要低得多,因此它被广泛应用于各种搜索场景中。


在这里二段性的体现是峰值的左边单调增,右边单调减。你可能会反驳给我们的数值不只有一个峰值,但是只要我们控制好条件,一定可以把范围压缩到只有一个峰值的情况,来看看该怎么处理:


  • nums[mid] < nums[mid + 1]说明在“上坡”,则可以使left = mid + 1(因为mid肯定不是峰值),向“峰”处压缩
  • nums[mid] > nums[mid + 1]说明在“下坡”,则应该使right = mid(mid可能是峰值),往“峰”处压缩


虽然开始left和right之间可能有多个峰值,但是随着left和right不断逼近,最后两者之间一定会压缩到一个峰值上,因为两者都是向“峰”不断靠近的,但是不会超过最终的“峰”。

望上文对你有帮助,谢谢你的阅览,后面会持续分享算法题目,大家可以关注一下。


2023.02.18


From:努力进大厂的新青年


相关文章
|
2月前
|
存储 Java 程序员
数据结构之 - 深入了解数组数据结构
数据结构之 - 深入了解数组数据结构
42 6
|
2月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
41 0
|
2月前
|
存储 算法 搜索推荐
探索常见数据结构:数组、链表、栈、队列、树和图
探索常见数据结构:数组、链表、栈、队列、树和图
112 64
|
4月前
|
算法 测试技术
【算法】二分算法——寻找旋转排序数组中的最小值
【算法】二分算法——寻找旋转排序数组中的最小值
|
4月前
|
算法
【算法】二分算法——寻找峰值
【算法】二分算法——寻找峰值
|
4月前
|
算法
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
|
2月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
39 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
2月前
|
存储 算法 定位技术
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
25 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
|
3月前
|
算法 前端开发 机器人
一文了解分而治之和动态规则算法在前端中的应用
该文章详细介绍了分而治之策略和动态规划算法在前端开发中的应用,并通过具体的例子和LeetCode题目解析来说明这两种算法的特点及使用场景。
一文了解分而治之和动态规则算法在前端中的应用
|
3月前
|
存储 Java
java数据结构,线性表顺序存储(数组)的实现
文章介绍了Java中线性表顺序存储(数组)的实现。线性表是数据结构的一种,它使用数组来实现。文章详细描述了线性表的基本操作,如增加、查找、删除、修改元素,以及其他操作如遍历、清空、求长度等。同时,提供了完整的Java代码实现,包括MyList接口和MyLinearList实现类。通过main函数的测试代码,展示了如何使用这些方法操作线性表。