算法练习-每日气温【单调栈】(思路+流程图+代码)

news2025/1/20 1:41:40

难度参考

        难度:困难

        分类:单调栈

        难度与分类由我所参与的培训课程提供,但需 要注意的是,难度与分类仅供参考。且所在课程未提供测试平台,故实现代码主要为自行测试的那种,以下内容均为个人笔记,旨在督促自己认真学习。

题目

        请根据每日气温列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用0来代替。

        示例1:

        输入: temperatures =[73,74,75,71,69,72,76,73]

        输出:[1,1,4,2,1,1≥0,0]

        提示:气温列表长度的范围是[1,30000]。每个气温的值的均为华氏度,都是在[30,100]范围内的整数。

思路

        初始化:创建一个栈来保存温度的索引,这样我们可以通过索引快速定位到温度值。同时,创建一个结果数组,其初始值全部为0,表示默认情况下没有更高的气温(或者说需要等待的天数为0)。

        遍历温度列表:对于温度列表中的每一个元素,我们进行以下操作:

        a. 检查栈:在将当前元素的索引添加到栈之前,我们需要检查栈顶元素。如果栈不为空且当前元素代表的温度大于栈顶元素索引对应的温度,那么我们找到了一个更高的气温。

        b. 更新结果和清理栈:当我们找到一个更高的温度时,计算当前索引与栈顶索引的差值,这个差值就是栈顶索引位置需要等待的天数,以观测到更高的气温。然后将栈顶元素弹出。重复这个过程,直到栈为空或者栈顶元素代表的温度大于等于当前温度。

        c. 索引入栈:将当前温度的索引入栈。这意味着对于后面的温度,如果有更高的温度出现,可以通过这个索引计算出需要等待的天数。

        返回结果:遍历完成后,结果数组中存储的就是对应位置需要等待的天数,以观测到更高的气温。返回这个结果数组。

示例

        假设你在一座城市里的连续几天里观测温度,你记录下来的温度如下:

温度列表: [73, 74, 75, 71, 69, 72, 76, 73]

        想象你有一堆小纸条,每个纸条上写着一天的温度和这一天是第几天。你的目标是对于每一天,找出需要等待多少天才能得到一个更高的温度。

        初始:

栈状态
            --------
              null
            --------
ans数组
        [0, 0, 0, 0, 0, 0, 0, 0]

        1. 你从第一天开始,手里拿着第一天的纸条(73度),因为还没有其他的纸条来比较,你就把它放在桌子上。

栈状态
            --------
              0
            --------
ans数组
        [0, 0, 0, 0, 0, 0, 0, 0]

        2. 第二天,你拿着第二天的纸条(74度)。你回头看桌子上的纸条,发现74度比73度高。这意味着,从第一天起,只需等待1天就会有更高的温度。于是,你在第一天的纸条上记下“等待1天”,然后把73度的纸条收走,把74度的纸条放在桌子上。(73度就是第0张纸条,74就是第1张纸条,温度列表中的[73, 74, 75, 71, 69, 72, 76, 73]以此类推)

栈状态
            --------
              1
            --------
ans数组
        [1, 0, 0, 0, 0, 0, 0, 0]

        3. 第三天,你拿着第三天的纸条(75度)。同样,你比较它和桌子上的纸条,发现75度比74度高。这意味着第二天之后,也只需等待1天就会有更高的温度。你在第二天的纸条上记下“等待1天”,收走74度的纸条,放下75度的纸条。

栈状态
            --------
              2
            --------
ans数组
        [1, 1, 0, 0, 0, 0, 0, 0]

        4. 接下来是71度和69度的两天,这两天的温度都没有超过桌子上的75度,所以你把这两天的纸条都放在桌子上,等待未来的某一天比它们高的温度。

栈状态
            --------
              2,3
            --------
ans数组
        [1, 1, 0, 0, 0, 0, 0, 0]
栈状态
            --------
              2,3,4
            --------
ans数组
        [1, 1, 0, 0, 0, 0, 0, 0]

        5. 第六天,温度是72度。你查看桌子上的纸条,首先发现69度,72度比它高,所以你在69度的纸条上记下“等待1天”,然后收走它。接着,你看到71度的纸条,72度也比它高,所以你在71度的纸条上记下“等待2天”,然后收走它。现在,桌子上只剩下75度的纸条,而72度比它低,所以你把72度的纸条也放在桌子上。

栈状态
            --------
              2,5
            --------
ans数组
        [1, 1, 0, 2, 1, 0, 0, 0]

        6. 第七天,温度是76度,这一天的温度比桌子上所有的纸条都要高。所以你依次将每张纸条拿起,记下等待的天数(对75度是4天,对72度是1天),然后将它们都收走。最后,你把76度的纸条放在桌子上。

栈状态
            --------
              6
            --------
ans数组
        [1, 1, 4, 2, 1, 1, 0, 0]

        7. 最后一天,温度是73度,但是这是最后一天了,我们不需要再记录更高温度的等待天数了,因为已经没有更多的天数了。

栈状态
            --------
              6,7
            --------
ans数组
        [1, 1, 4, 2, 1, 1, 0, 0]

        通过这个过程,你为每一天都记录了需要等待更高温度的天数,最终得到的结果就是:[1, 1, 4, 2, 1, 1, 0, 0]。

梳理

        这个方法之所以有效,归根到底是因为它利用了一个叫做"单调栈"的数据结构来优化查找过程。下面是几个关键点来解释为什么这样做能够实现目标:

        1. 单调性:栈用于维护温度的索引,这些索引对应的温度是单调递减的。这意味着栈顶的温度总是最小的。这样做的好处是,当你遍历到一个新的温度时,只需要与栈顶元素比较,就可以知道是否存在一个更高的温度。如果新的温度更高,那么栈顶元素及所有比新温度低的元素都可以找到一个更高的温度,因此可以计算等待天数并更新`ans`数组。

        2. 有效地找到更高的温度:当你遇到一个比栈顶温度高的新温度时,这说明你找到了从栈顶索引对应的天数起,第一个更高的温度。因为栈是递减的,所以栈中所有低于新温度的日子都会被连续弹出,直到遇到一个比新温度更高的日子或栈为空。这样,对于每个被弹出的日子,你都可以确定它们等待更高温度的确切天数,这是通过计算当前温度的索引与被弹出的索引之间的差来实现的。

        3. 避免重复比较:通过仅将尚未找到更高温度的日子的索引放入栈中,我们避免了对每个新日子进行全面比较。这种方法只比较那些有可能在未来遇到更高温度的日子,从而大大减少了比较的次数。

        4. 时间复杂度优化:由于每个元素最多被压入栈一次,且从栈中弹出一次,遍历温度列表和处理栈的操作的总时间复杂度为O(n),其中n是温度列表的长度。这比一个简单的嵌套循环(时间复杂度为O(n^2))要高效得多。

        综上所述,通过使用单调栈,我们能够高效地为每一天找到等待更高温度的天数。这种方法充分利用了"先进后出"的栈特性和温度之间的相对单调性,优化了查找过程,确保了整个算法的效率和有效性。

代码

#include <vector>     // 引入vector库,用于存储温度数据和结果数组
#include <stack>      // 引入stack库,用于实现单调栈
#include <iostream>   // 引入iostream库,用于输入输出

using namespace std;

vector<int> dailyTemperatures(vector<int>& temperatures) {
    int n = temperatures.size();   // 获取输入温度数组的长度
    vector<int> ans(n, 0);         // 初始化结果数组,大小与输入数组相同,默认值为0
    stack<int> indexStack;         // 存储温度索引的单调栈

    for (int i = 0; i < n; ++i) {  // 遍历温度数组
        while (!indexStack.empty() && temperatures[i] > temperatures[indexStack.top()]) {
            // 当栈不为空且当前温度高于栈顶温度时,进行循环
            // 获取栈顶元素(较低温度的索引)
            int prevIndex = indexStack.top();
            indexStack.pop();   // 弹出栈顶元素
            ans[prevIndex] = i - prevIndex;  // 计算当前天数与更高温度天数的差值,存储到结果数组中
        }
        indexStack.push(i);   // 将当前温度的索引入栈
    }
    return ans;   // 返回结果数组
}

int main() {
    vector<int> temperatures = {73, 74, 75, 71, 69, 72, 76, 73};  // 定义温度数组
    vector<int> result = dailyTemperatures(temperatures);   // 调用函数获取结果数组

    for (int days : result) {   // 遍历结果数组
        cout << days << " ";   // 输出每个元素(表示所需的天数)
    }
    cout << endl;

    return 0;
}
  • 时间复杂度: O(n)

  • 空间复杂度: O(n)

打卡

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1458112.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

npm run dev运行出现NODE_OPTIONS=--max_old_space_size=4096 vite --mode dev --host?

问题描述 PS E:\AWorkDataease\DataEase\core\core-frontend> npm run dev dataease0.0.0 dev NODE_OPTIONS–max_old_space_size4096 vite --mode dev --host 0.0.0.0 ‘NODE_OPTIONS’ 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 解决方案 遇到…

【8】知识加工

一、概述 对信息抽取/知识融合后得到的“事实”进行知识推理以拓展现有知识、得到新知识。 知识加工主要包括三方面内容&#xff1a;本体构建、知识推理和质量评估。 二、本体构建 1.本体 定义&#xff1a;本体是用于描述一个领域的术语集合&#xff0c;其组织结构是层次结…

Python数据科学:线性回归

4.5线性回归 线性回归是解决回归问题的常用模型。 实例&#xff1a;简单线性回归 def skLearn13():线性回归:return:#简单的一元一次方程#斜率为a,截距为b#yaxb#创建线性数据rng np.random.RandomState(0)x 10 * rng.rand(50)y 2*x - 5 rng.randn(50)#绘制数据集plt.sca…

osqp-eigen学习

OSQP文档学习 参考博客&#xff1a; &#xff08;1&#xff09;二次规划&#xff08;QP&#xff09;与OSQP求解器 &#xff08;2&#xff09;如何使用OSQP-Eigen osqp-eigen 1 osqp-eigen接口 以下列问题的求解为例&#xff1a; s.t. 1 ≤ x 1 ≤ 1.5 1≤x_1≤1.5 1≤x1​≤…

【C#】使用代码实现龙年春晚扑克牌魔术(守岁共此时),代码实现篇

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握。…

Linux-目录I/O-004

学习重点&#xff1a; 1.目录I/O的函数接口 2.目录的遍历&#xff0c;目录的递归遍历 1.【mkdir】 1.1函数原型 【int mkdir(const char *pathname, mode_t mode);】1.2函数功能 创建目录文件1.3函数参数 1.3.1【pathname】 文件路径1.3.2【mode】 文件的权限1.4返回值 …

区块链 之 默克尔树

默克尔树简介 欢迎阅读 BTC网络 之 区块裁剪 什么是默克尔树&#xff1f; 默克尔树&#xff08;Merkle Tree&#xff09;是一种树状数据结构&#xff0c;被广泛用于比特币等区块链系统中&#xff0c;用于高效地组织和验证数据的完整性。这个树状结构由唯一的根哈希值标识&am…

matplotlib图例使用案例1.1:在不同行或列的图例上添加title

我们将图例进行行显示或者列显示后&#xff0c;只能想继续赋予不同行或者列不同的title来进行分类。比较简单的方式&#xff0c;就是通过ax.annotate方法添加标签&#xff0c;这样方法复用率比较低&#xff0c;每次使用都要微调ax.annotate的显示位置。比较方便的方法是在案例1…

PyTorch使用Tricks:Dropout,R-Dropout和Multi-Sample Dropout等 !!

文章目录 1、为什么使用Dropout&#xff1f; 2、Dropout的拓展1&#xff1a;R-Dropout 3、Dropout的拓展2&#xff1a;Multi-Sample Dropout 4、Dropout的拓展3&#xff1a;DropConnect 5、Dropout的拓展4&#xff1a;Standout 6、Dropout的拓展5&#xff1a;Gaussian Dropout …

微信小程序开发:通过wx.login()获取用户唯一标识openid和unionid

下面代码展示了 openid 的获取过程。 想获取 unionid 需要满足条件&#xff1a;小程序已绑定到微信开放平台账号下&#xff0c;不然只会返回 openid。 【相关文档】 微信小程序开发&#xff1a;appid 和 secret 的获取方法 wx.login({success (res) {if (res.code) {// 发起网…

十二:枚举与注解

文章目录 01、枚举类的使用1.1、枚举类的理解1.2、自定义枚举类1.3、使用enum关键字定义枚举类1.4、Enum类中的常用方法1.5、使用enum关键字定义的枚举类实现接口 02、注解的使用2.1、注解的理解2.3、如何自定义注解2.4、jdk中4个基本的元注解的使用12.5、jdk中4个基本的元注解…

解锁创意灵感,探索FlutterExampleApps项目的奥秘

解锁创意灵感&#xff0c;探索FlutterExampleApps项目的奥秘 项目简介 FlutterExampleApps项目是一个包含各种示例应用链接的仓库&#xff0c;旨在演示Flutter应用开发中的各种功能、特性和集成。 项目包含了以下几个部分&#xff0c;每个部分都涵盖了不同的内容和主题&…

VO、DTO、DO、BO、PO

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 VO、DTO、DO、BO1.概念阿里Java开发手册分层领域模型&#xff1a; 2. VO 和 DTO 使用场景以下是一个使用VO和DTO的典型案例&#xff1a; 3.BO和DTO的区别 案例 VO、…

分享两个版本的数字孪生技术栈,都是AI回答的,较为精准

版本一&#xff1a; 数字孪生应用到的技术栈包括但不限于&#xff1a; 3D建模&#xff1a;数字孪生需要建立虚拟的三维模型&#xff0c;因此需要使用3D建模软件如AutoCAD、SketchUp、3ds Max等。 数据采集&#xff1a;数字孪生需要采集大量实时的物理数据&#xff0c;如传感…

为什么从没有负值的数据中绘制的小提琴图(Violin Plot)会出现负值部分?

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 小提琴图&#xff08;Violin Plot&#xff09; 是一种用于展示和比较数据分布的可视化工具。它结合了箱形图&#xff08;Box Plot&#xff09;和密度图&#xff08;Kernel Density Plot&#xff09;的特…

hive load data未正确读取到日期

1.源数据CSV文件日期字段值&#xff1a; 2.hive DDL语句&#xff1a; CREATE EXTERNAL TABLE test.textfile_table1(id int COMMENT ????, name string COMMENT ??, gender string COMMENT ??, birthday date COMMENT ????,.......) ROW FORMAT SERDE org.apache.…

QT中事件过滤器

Qt添加事件过滤器&#xff0c;设置拖放listWidget、TreeWidget、TableWidget控件。 #include "mainwindow.h" #include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this)…

UML---活动图

活动图概述 活动图&#xff08;Activity Diagram&#xff09;是UML&#xff08;Unified Modeling Language&#xff0c;统一建模语言&#xff09;中的一种行为建模工具&#xff0c;主要用于描述系统或业务流程中的一系列活动或操作。活动图通常用于描述用例中的行为&#xff0c…

SimpleDateFormat为什么是线程不安全的?

目录 在日常开发中&#xff0c;Date工具类使用频率相对较高&#xff0c;大家通常都会这样写&#xff1a;这很简单啊&#xff0c;有什么争议吗&#xff1f;格式化后出现的时间错乱。看看Java 8是如何解决时区问题的&#xff1a;在处理带时区的国际化时间问题&#xff0c;推荐使用…

[创业之路-88/管理者与领导者-128]:企业运行分层模型、研发管理全视野

目录 一、企业分层模型 1.1 愿景层 1.2 战略目标层 1.3 战术方法层 1.4 市场业务层 1.5 项目执行层 1.6 资源层 二、研发全视野、全流程 2.1 市场 2.2 战略规划 2.3 产品研发 2.3.1 概述 2.3.2 项目管理 2.3.3 研发业务管理&#xff08;研发经理*N) – 管技术流程…