【力扣刷题 | 第九天】150 逆波兰 239滑动窗口最大值

news2024/11/25 16:19:26

目录

前言: 

150. 逆波兰表达式求值 - 力扣(LeetCode)

239. 滑动窗口最大值 - 力扣(LeetCode)

 总结:


前言: 

本片仍然是利用栈与队列的思想来解决实际问题,希望各位小伙伴可以和我一起坚持下去,征服力扣。

150. 逆波兰表达式求值 - 力扣(LeetCode)

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

有效的算符为 '+'、'-'、'*' 和 '/' 。
每个操作数(运算对象)都可以是一个整数或者另一个表达式。
两个整数之间的除法总是 向零截断 。
表达式中不含除零运算。
输入是一个根据逆波兰表示法表示的算术表达式。
答案及所有中间计算结果可以用 32 位 整数表示。

在这里我们要先介绍一下什么是逆波兰表达式:
        逆波兰表达式,又称后缀表达式,是一种数学表达式的表示方法。在逆波兰表达式中,操作符在操作数之后,因此也被称为后缀表示法。例如,表达式 "3 + 4" 在逆波兰表达式中表示为 "3 4 +"。逆波兰表示法可以通过栈来实现,首先将所有操作数入栈,每当遇到一个操作符时,弹出栈顶的两个操作数进行运算,并将运算结果再次压入栈中,直到整个表达式处理完毕。与传统的中缀表达式相比,逆波兰表达式的优点是可以不用考虑运算符优先级的问题。 具体文章可以看【夜深人静学数据结构与算法 | 第二篇】后缀(逆波兰)表达式_我是一盘牛肉的博客-CSDN博客 ​​​​​​

非常建议大家先看这篇文章在做这道题,理解了逆波兰运算的思想之后,这道题根本不难!

解法:

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> d1;
        for (int i = 0; i < tokens.size(); i++) {
            if (tokens[i] != "+" && tokens[i] != "-" && tokens[i] != "*" && tokens[i] != "/") {
                d1.push(stoi(tokens[i]));
            }
            if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {
                int a = d1.top();
                d1.pop();
                int b = d1.top();
                d1.pop();
                int sum = 0;
                if (tokens[i] == "+") {
                    sum = b + a;
                    d1.push(sum);
                }
                else if (tokens[i] == "-") {
                    sum = b - a;
                    d1.push(sum);
                }
                else if (tokens[i] == "*") {
                    sum = b * a;
                    d1.push(sum);
                }
                else if (tokens[i] == "/") {
                    sum = b / a;
                    d1.push(sum);
                }
            }
        }
        int final = d1.top();
        return final;
    }
};

 这里由于提供的数组是char类型的,我们自己创建的栈是int类型的,因此入栈的时候需要强制类型转换:stoi是C++标准库中string类型转int类型的函数,d1.push(stoi(tokens[i]))则将字符串类型的元素tokens[i]转换为整数类型并且将其压入栈d1当中。这段代码的作用是将不是操作符的元素压入栈中,以便计算逆波兰表达式时使用。

​​​​​​​239. 滑动窗口最大值 - 力扣(LeetCode)

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 。

 解法1:双指针思路时间复杂度为O(nums.size()*k),但是这种解法无法解决最后一个测试用例(也就是待测试数组元素极多的情况下),会存在超时问题。而这道题的难点就在于如何解决暴力超时的问题,遍历数组我们无法忽略,因此应该是如何查找k个元素里面的最大值,这是优化时间复杂度的关键

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int>d1;
        int left=0;
        int right=k-1;
        int max=1;
        int temp=0;
        for(int i=0;i<nums.size();i++)
        {
            if(max>nums[i])
            {
                temp=nums[i]-1;
                max=temp;
            }
        }
        while(right<=nums.size()-1)
        {
            for(int i=left;i<=right;i++)
            {
                if(max<nums[i])
                {
                    max=nums[i];
                }
            }
            d1.push_back(max);
            left++;
            right++;
            max=temp;
        }
        return d1;
    }
};

解法2:队列解法

我们抛弃了传统的统计窗口数值时使用的for循环从(left到right),采用了队列的思想,我们就创建一个k长度的队列,每一次更新队列都是去尾添头,这样就省略了一个for循环,大大降低了时间复杂度

此时我们建立一个队列,这个队列的最大值总是在头部,这样我们只需要让队列遍历这个数字,每次输入自己的头部最大值就好了。

class Solution {
private:
    class structQueue { 
    public:
        deque<int> que; 
      
        void realpop(int value) {
            if (!que.empty() && value == que.front())//不是所有的元素都执行pop,因为有的元素进入这个队列之后如果后面有值大于他就 会被顶出去,因此我们这里pop的是真正存在的值。
             {
                que.pop_front();
            }
        }
        //我们一直pop掉比value小的值
        void push(int value) {
            while (!que.empty() && value > que.back()) {
                que.pop_back();
            }
            que.push_back(value);

        }
        //这样头部始终都是最大值。
        int front() {
            return que.front();
        }
    };
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> result;
        structQueue que;      
        for (int i = 0; i < k; i++) {
            que.push(nums[i]);
        }
        result.push_back(que.front()); 
        for (int i = k; i < nums.size(); i++) {
            que.realpop(nums[i - k]); 
            que.push(nums[i]); 
            result.push_back(que.front()); 
        }
        return result;
    }
};

题解二讲解:假设我们要求1,3,-1,-3,5,3,2,1数组,k值=3时,滑动窗口的最大值 

我们在让数组元素进队的时候为了让头部始终都是最大值,采取以下操作:

1.如果新入的数字比队列里的元素都大,我们就弹出队列里的元素,让这个新入的数字入队成为头部。

本来元素挨个入队后:

进行操作后(因为1比3小,我们就让1弹出)结果为3:

 得到最大值为3,队列向后移动,-3小于前两个值,因此不弹出,结果为3 3

 此时再向后移动,因为5大于所有的数字,因此全部弹出,结果为3 3 5

 再向后移动一位,3比5小,录入其中,结果为3 3 5 5;

 再向后移动一位,2比5小,录入其中,结果为3 3 5 5 5:

 再向后移动一位,因为此时队列已满,因此我们要弹出末尾元素5,然后再录入,因为整个队列都是降序,因此5弹出之后的队头仍然是整个队的最大值,结果为3 3 5 5 5 3.

为了方便阅读,我们自己在入口那里写的是将后面的数插入到队列中,将队列末尾的数删去。

但是实际上因为我们总是在维护头部的数据最大,因此我们在插入的时候就已经删除了部分数据,例如最开始的时候数列应该是1,3,-1.但是由于1比3小,绝对不可能成为这个窗口的最大值,因此我们就已经删除了1,那么在插入之后,我们实际上就不需要对末尾的数进行删除,但是为了方便阅读,我们还是加上了删除末尾元素,那么我们就在删除的时候进行判断,如果此时要删除的数字是末尾元素的话,再进行删除(参考情况5 3 2到3 2 1),此时就是因为之前一直符合递减数列(5并没有机会弹出),1插入不进去,我们就要手动删除末尾元素5,也就是利用我们自己写的删除函数。

插入的时候就已经弹出了。

 队列满了之后删除头部:

 总结:

        这两道题一道用到了队列,一道用到了栈,都是很不错的经典例题,可以极大的提高我们对于队列和栈的应用水平,我们应该把这两个题吃透,搞清楚背后的实现代码逻辑。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

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

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

相关文章

chatgpt赋能python:Python断言之等于两个值其中一个

Python断言之等于两个值其中一个 在Python编程中&#xff0c;我们经常需要对程序进行断言&#xff0c;以判断程序是否正确地运行。其中一种常见的断言方式是判断某个方法的结果是否等于两个值中的其中一个。本文将介绍如何在Python中实现这种断言&#xff0c;并探讨其在实际应…

⑨电子产品拆解分析-触摸化妆镜

⑨电子产品拆解分析-触摸化妆镜 一、功能介绍二、电路分析以及器件作用1、电源部分2、触摸部分3、灯光控制部分三、数据手册以及其它资料1、注意点2、数据手册汇总一、功能介绍 ①短按白光、暖光、冷光三档色温切换;②长按支持无极调光;③三档调亮度关机记忆当前亮度功能;二…

chatgpt赋能python:Python模块更新技巧详解

Python模块更新技巧详解 为什么需要更新Python模块&#xff1f; Python语言自问世以来一直在得到广泛的应用&#xff0c;其中最大的原因在于它的灵活性和可扩展性。Python拥有丰富的模块库&#xff0c;覆盖了各种不同的应用场景。然而&#xff0c;由于软件环境不断发展&#…

服务器配置远程vscode

1 使用sftp同步远程代码 打开vscode&#xff0c;在扩展种搜索sftp&#xff0c;点击安装。   按住快捷键shiftctrlp&#xff0c;可以打开界面顶部的命令行&#xff0c;输入sftp&#xff0c;点击如下图的config选项&#xff1a;   会自动在.vscode目录下创建一个名为sftp.j…

photoscan(metashape)跑GPS辅助的无人机影像SfM(空三)教程

刚打开的photoscan界面如下图所示&#xff1a;   然后&#xff0c;点击工作区左上角的添加堆块选项&#xff1a;   可以看到新增了一个名为“Chunk 1”的堆块&#xff0c;然后&#xff0c;右击“Chunk 1”&#xff0c;依次选择add、添加照片&#xff1a;   即可弹出照…

踩坑系列 Spring websocket并发发送消息异常

文章目录 示例代码WebSocketConfig配置代码握手拦截器代码业务处理器代码 问题复现原因分析解决方案方案一 加锁同步发送方案二 使用ConcurrentWebSocketSessionDecorator方案三 自研事件驱动队列&#xff08;借鉴 Tomcat&#xff09; 总结 今天刚刚经历了一个坑&#xff0c;非…

云原生之使用Docker部署wordpress网站

云原生之使用Docker部署wordpress网站 一、wordpress介绍二、检查本地docker环境1.检查docker状态2.检查docker版本 三、下载wordpress镜像四、创建数据库1.创建数据目录2.创建mysql数据库容器3.查看mysql容器状态4.远程客户端测试连接数据库 五、部署wordpress1.创建wordpress…

java开发——程序性能的优化方法

java开发——程序性能的优化方法 1、算法逻辑优化2、redis缓存优化3、异步编排4、MQ削峰填谷5、预加载6、sql调优7、jvm调优8、集群搭建 后端开发必须学习的优化思想&#xff01; 1、算法逻辑优化 (1) 什么算法优化&#xff1f; 算法优化的思想就是&#xff0c;对于同一个问题…

ll 内容详解

linux的数据存储是以block&#xff08;块&#xff09;为单位的 &#xff1a; 1个block 4 KB 4096 字节 1KB 1024 字节[rootCTF-RHCSA-2 ~]# ll -sh total 76K &#xff08;列表中 所有文本文件 总共占用磁盘空间的KB大小 &#xff09;&#xff08;root用户家目录中…

cortex A7核按键中断实验

cortex A7核按键中断实验 一、分析电路图 实验目的&#xff1a;完成板子三个按键操作 1.1 电路图IO口 KEY1------>PF9 KEY2------>PF7 KEY3------>PF8 1.2 工作原理 KEY1 ------> PF9 ------> 按键触发方式&#xff1a;下降沿触发 KEY2 ------> PF7 …

ElasticSearch安装与介绍

目录 ElasticSearch安装与介绍Elastic Stack简介ElasticsearchLogstashKibanaBeats ElasticSearch快速入门简介下载单机版安装启动ElasticSearch 错误分析错误情况1错误情况2错误情况3 ElasticSearch-Head可视化工具通过Docker方式安装通过Chrome插件安装 ElasticSearch中的基本…

docker部署prometheus+grafana+alertmanager+dingtalk实现钉钉告警

目录 docker安装准备工作镜像拉取容器启动启动node-exporter启动prometheus启动grafana启动webhook-prometheus-dingtalk启动alertmanager所有容器启动成功如下 将prometheus和alertmanager进行关联在prometheus目录下新建一个rules.yml文件的告警规则修改prometheus.yml文件&a…

NLP学习笔记十二-skip-gram模型求解

NLP学习笔记十一-skip-gram模型求解 上一篇文章&#xff0c;我们见到了skip-gram模型的原理&#xff0c;这里我们在陈述一下skip-gram模型其实是基于分布相似性原理来设计的&#xff0c;在skip-gram模型中&#xff0c;他认为一个词的内涵可以由他的上下文文本信息来概括&#…

AcWing 837. 连通块中点的数量

题目如下&#xff1a; 给定一个包含 n个点&#xff08;编号为 1∼ n&#xff09;的无向图&#xff0c;初始时图中没有边。 现在要进行 m 个操作&#xff0c;操作共有三种&#xff1a; C a b&#xff0c;在点 a和点 b之间连一条边&#xff0c;a 和 b 可能相等&#xff1b;Q1 …

【iMessage苹果日历推真机群控】使用虚拟化平台创建一个 macOS 虚拟机

PC 虚拟机上部署群控推送并模拟苹果 iMessage 推送消息是比较复杂的任务。由于苹果的 iMessage 服务是基于苹果设备和操作系统的&#xff0c;模拟 iMessage 推送需要考虑苹果的生态系统和安全机制。 以下是一种可能的方法&#xff0c;但请注意这是一个高级设置&#xff0c;需要…

chatgpt赋能python:Python编程中的放大代码技巧

Python 编程中的放大代码技巧 Python 是一门广泛应用于各个领域的编程语言。由于它易学易用、可移植性好、开发效率高等特点&#xff0c;使其在人工智能、大数据分析、网站开发等领域被广泛应用。在实际编程中&#xff0c;随着代码量的增加&#xff0c;需要更好地组织和管理代…

BFS 广度优先搜索

广度优先搜索BFS&#xff08;Breadth First Search&#xff09;也称为宽度优先搜索&#xff0c;它是一种先生成的结点先扩展的策略&#xff0c;类似于树的层次遍历。 在广度优先搜索算法中&#xff0c;解答树上结点的扩展是按它们在树中的层次进行的。首先生成第一层结点&#…

TS系列之keyof详解,示例

文章目录 前言一、keyof是什么总结 前言 如果你用过TS的工具类型&#xff0c;Partial、Required、Pick、Record。那么你可能看过他们内部实现都有共同点就是keyof关键字。即使没有见过&#xff0c;那么下面就一起来了解一下&#xff0c;keyof关键字的详细作用吧。 一、keyof是…

Filebeat详细介绍,下载和启动,日志读取和模块设置等

目录 Filebeat介绍为什么要用Filebeat&#xff1f;架构下载启动读取文件自定义字段输出到ElasticSearch Filebeat工作原理harvesterprospectorinput启动命令参数说明 部署Nginx读取Nginx中的配置文件Modulenginx module 配置配置filebeat测试错误1错误2 Filebeat 介绍 Filebe…

Java开发中的常见问题和解决方法:如何解决常见的性能和bug问题

章节一&#xff1a;引言 在Java开发中&#xff0c;我们经常会面临各种各样的问题&#xff0c;包括性能问题和Bug。这些问题可能会导致应用程序的运行变慢、不稳定甚至崩溃。本文将介绍一些常见的Java开发问题&#xff0c;并提供解决这些问题的方法和技巧&#xff0c;帮助开发人…