【算法训练笔记】栈的OJ题

news2024/11/25 8:20:36

       🔥🔥 欢迎来到小林的博客!!
      🛰️博客主页:✈️林 子
      🛰️博客专栏:✈️ 小林的算法训练笔记
      🛰️社区 :✈️ 进步学堂
      🛰️欢迎关注:👍点赞🙌收藏✍️留言

目录

  • 1047. 删除字符串中的所有相邻重复项
  • 844. 比较含退格的字符串
  • 227. 基本计算器 II
  • 394. 字符串解码
  • 946. 验证栈序列

1047. 删除字符串中的所有相邻重复项

题目链接:1047. 删除字符串中的所有相邻重复项

题目描述:

给出由小写字母组成的字符串 S重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例:

输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。

提示:

  1. 1 <= S.length <= 20000
  2. S 仅由小写英文字母组成。

解题思路:

我们只需要把字符入栈,每次入栈前和栈顶元素进行比较,如果字符相同则把栈顶POP掉,并且此次元素也不Push,这样即完成一次删除操作。反之则把元素push入栈。 因为返回值是一个字符串,所以我们可以拿字符串来模拟栈,尾删对应的是出栈,尾插对应的是入栈。

动图详解:

在这里插入图片描述

代码:

class Solution {
public:
    string removeDuplicates(string s) {
        string st;//用字符串模拟栈
        for(auto& ch : s)
        {
            if(st.size() > 0 && st.back() == ch)
            {
                st.pop_back();
            }else
            {
                st.push_back(ch);
            }
        }
        return st;
    }
};

运行结果:

在这里插入图片描述

844. 比较含退格的字符串

题目链接:844. 比较含退格的字符串

题目描述:

给定 st 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true# 代表退格字符。

**注意:**如果对空文本输入退格字符,文本继续为空。

示例 1:

输入:s = "ab#c", t = "ad#c"
输出:true
解释:s 和 t 都会变成 "ac"。

示例 2:

输入:s = "ab##", t = "c#d#"
输出:true
解释:s 和 t 都会变成 ""。

示例 3:

输入:s = "a#c", t = "b"
输出:false
解释:s 会变成 "c",但 t 仍然是 "b"。

提示:

  • 1 <= s.length, t.length <= 200
  • st 只含有小写字母以及字符 '#'

解题思路:

和上一题是一样的,只不过这次我们是遇到#则删除前一个。而上一题是当前字符和栈顶字符相等则删除栈顶字符,这个则是遇到#删除栈顶字符。然后两个字符串都做一次上面那道题的操作,然后比较一小是否相等即可,不过这里也有一个小细节,那就是#号可以出现在第一个字符,这里需要特殊判断一下。因为步骤和上面几乎一模一样,所以动图就不画了,搞懂了上一题这一题自然也能秒懂。

代码:

class Solution {
public:
    bool backspaceCompare(string s, string t) {
        string st1; //存储s
        string st2; //存储t
        for(auto& ch : s)
        {
            if(st1.size() > 0 && ch == '#') st1.pop_back();
            else if(ch != '#') st1.push_back(ch);
        }
        //和上面操作一模一样
        for(auto& ch : t)
        {
            if(st2.size() > 0 && ch == '#') st2.pop_back();
            else if(ch != '#')st2.push_back(ch); //#符号不能入栈
        }
        return st1 == st2; //相等返回true
    }
};

运行结果:

在这里插入图片描述

227. 基本计算器 II

题目链接:227. 基本计算器 II

题目描述:

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。

整数除法仅保留整数部分。

你可以假设给定的表达式总是有效的。所有中间结果将在 [-231, 231 - 1] 的范围内。

**注意:**不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval()

示例 1:

输入:s = "3+2*2"
输出:7

示例 2:

输入:s = " 3/2 "
输出:1

示例 3:

输入:s = " 3+5 / 2 "
输出:5

提示:

  • 1 <= s.length <= 3 * 105
  • s 由整数和算符 ('+', '-', '*', '/') 组成,中间由一些空格隔开
  • s 表示一个 有效表达式
  • 表达式中的所有整数都是非负整数,且在范围 [0, 231 - 1]
  • 题目数据保证答案是一个 32-bit 整数

解题思路

因为这运算只有 +,-,*,/四则运算。所以我们只需要用一个栈来存储数据,再用一个char op变量来存储符号。当走到数字的时候遇到 X 或者 / 号。那么就从栈中pop出2个数据。进行运算后再重新放回队列,如果记录的是-号。那么我们往队列push的值需要 乘上一个-1。到最后再把栈里的值全部相加起来即可。这里需要注意一个小细节,就是我们的op需要初始化成’+'号。因为只有op为’+‘ ,我们才会把数据push进栈中。

比如下面有一个例子,3+2*2-5 ,我们来动图模拟一下。

在这里插入图片描述

还有一点要注意的是,leetcode给的数据中是有可能会包含空格,所以遇到空格我们要跳过。

在这里插入图片描述

代码:

class Solution {
public:
    int calculate(string s) {
        char op = '+';
        stack<int> st;
        int n = s.size(), i = 0;
        while(i < n)
        {
            if(s[i] == ' ') i++;  //跳过空格
            else if(s[i] >= '0' && s[i] <= '9')
            {
                //遇到数据了,数据可能是多位数,所以我们要全部截取
                int val = 0; 
                while(s[i] >= '0' && s[i] <= '9') val = val * 10 + (s[i++] - 48); 

                //如果op是+号,我们要入栈,如果是-号,我们需要 * -1 再入栈,如果是 * 和 / 先出栈,再val和出栈的数进行运算
                if(op == '+')
                    st.push(val);
                else if(op == '-')
                    st.push(val* -1);
                else 
                {
                    //是 * 和 / ,我们把栈顶元素拿出来运算,运算完再push到栈中
                    int top = st.top();
                    st.pop();
                    switch(op)
                    {
                        case '*' : st.push(top * val);  break;
                        case '/' : st.push(top/val); break;
                    }
                }
            }else 
            {
                //遇到符号了,直接替换符号
                op = s[i++]; 
            }
        }

        //把栈中的元素全部取出来相加
        int sum = 0 ;
        while(!st.empty())
        {
            sum += st.top();
            st.pop();
        }
        return sum;
    }
};

运行结果:

在这里插入图片描述

394. 字符串解码

题目链接:字符串解码

题目描述:

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a2[4] 的输入。

示例 1:

输入:s = "3[a]2[bc]"
输出:"aaabcbc"

示例 2:

输入:s = "3[a2[c]]"
输出:"accaccacc"

示例 3:

输入:s = "2[abc]3[cd]ef"
输出:"abcabccdcdcdef"

示例 4:

输入:s = "abc3[cd]xyz"
输出:"abccdcdcdxyz"

提示:

  • 1 <= s.length <= 30
  • s 由小写英文字母、数字和方括号 '[]' 组成
  • s 保证是一个 有效 的输入。
  • s 中所有整数的取值范围为 [1, 300]

解题思路:

这一题我们依旧要用栈来解决,我们需要用2个栈,一个栈用来存放数字,一个栈用来存放字符串。当遇到数字时,提取数字并入数字栈。当遇到[号时,提取字符串并入字符栈。当遇到]时,也就是解码。我们需要从字符栈种拿字符,从数字栈种拿数字。随机拼接成一个新字符串,把新字符串接入到上一个栈顶的后面。我们分四种情况讨论。

情况1:遇到数字

遇到数字,那么数字可能也是多个字符串组成,所以我们需要把数字提取出来,放入 nums栈中。

情况2:遇到 [

遇到[说明要开始提取字符了,那么从当前下标的下一个位置开始提取字符串。提取完字符串后入到 strs栈中。

情况3:遇到 ]

遇到 [ 说明我们要开始解密了,我们分别提取strs栈和nums栈中的栈顶。获得一个数字k和一个字符串str。我们循环k次,每次循环都加上一个str。最后需要把strs接到栈顶的尾部,因为我们不确定前面是否还有字符。

情况4:遇到字符

遇到字符说明数字只有1,所以我们只需要把字符提取出来,接入到strs栈顶的尾部即可。

需要注意一些小细节,那就是当strs栈为空的时候,我们是无法把字符串接入到栈顶的。所以我们一开始需要push一个空串进strs栈。这样后面的字符串往空串后面拼接,还是原来的样子。

动图演示:

在这里插入图片描述

动图中没有显示空串,其实最底下是有个空串的。否则后面的cacacacacaca接入到栈顶元素尾部是会报错的。

代码:

class Solution {
public:
    string decodeString(string s) {
        stack<int> nums;
        stack<string> strs; 
        strs.push(""); //先让空串入栈
        int i = 0 , n = s.size();
        while(i < n)
        {
            //第一种情况,如果遇到数字
            if(s[i] >= '0' && s[i] <= '9')
            {
                int val = 0;
                //拼接所有数字
                while(s[i] >= '0' && s[i] <= '9') val = val * 10 + (s[i++] - 48); 
                //拼接完数字入栈
                nums.push(val);
            }
            else if(s[i] == '[') //第二章情况,遇到 [ 
            {
                //从i的下一个位置开始提取字符
                string val; 
                i++; 
                while(s[i] >= 'a' && s[i] <= 'z')val += s[i++]; 
                //提取的字符入栈
                strs.push(val);
            }else if(s[i] == ']') // 第三种情况,遇到 ]
            {
                //分别从nums和strs中提取栈顶元素
                int k = nums.top();
                nums.pop();
                string tmp = strs.top();
                strs.pop();

                //将 k 次 tmp字符串接入到strs栈顶的尾部
                while(k--)
                {
                    strs.top() += tmp;
                }
                i++; //跳到下一个位置
            }else{
                //第四种情况,遇到字符
                //直接提取字符,接入到栈顶尾部
                string val; 
                while(i < n && s[i] >= 'a' && s[i] <= 'z')val += s[i++]; 
                //接入到栈顶尾部
                strs.top() += val;
            }
        }
        return strs.top(); //返回栈顶元素
    }
};

运行结果:

在这里插入图片描述

946. 验证栈序列

题目链接: 946. 验证栈序列

题目描述:

给定 pushedpopped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true;否则,返回 false

示例 1:

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1

示例 2:

输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
输出:false
解释:1 不能在 2 之前弹出。

提示:

  • 1 <= pushed.length <= 1000
  • 0 <= pushed[i] <= 1000
  • pushed 的所有元素 互不相同
  • popped.length == pushed.length
  • poppedpushed 的一个排列

解题思路:

我们可以用一个指针指向popped数组,然后疯狂让pushed数组的值入栈。然后监测栈顶元素是否等于当前指向的popped元素。如果等于则说明出栈,一直出栈到栈顶元素不等于popped为止。最后如果栈的元素不为空,说明出栈顺序是错误的。反之则是正确的。

动图演示:

在这里插入图片描述

如果循环结束,栈为空,则说明poped的出栈顺序是正确的。反之则说明是错误的。

代码:

class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        stack<int> st; 
        for(int i = 0 , j = 0 ; i < pushed.size() ; i++)
        {
            st.push(pushed[i]);
            while(!st.empty() && st.top() == popped[j])
            {
                st.pop();
                j++;
            }
        }
        return st.empty();
    }
};

运行结果:

在这里插入图片描述

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

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

相关文章

rsa加密解密java和C#互通

前言 因为第三方项目是java的案例&#xff0c;但是原来的项目使用的是java&#xff0c;故需要将java代码转化为C#代码&#xff0c;其中核心代码就是RSA加密以及加签和验签&#xff0c;其他的都是api接口请求难度不大。 遇到的问题 java和c#密钥格式不一致&#xff0c;java使…

C++QT day3

1> 自行封装一个栈的类&#xff0c;包含私有成员属性&#xff1a;栈的数组、记录栈顶的变量 成员函数完成&#xff1a;构造函数、析构函数、拷贝构造函数、入栈、出栈、清空栈、判空、判满、获取栈顶元素、求栈的大小 2> 自行封装一个循环顺序队列的类&#xff0c;包含…

backward问题记录

大致问题是这样的 模型先计算一个输出 然后根据这个输出&#xff0c;用lbfgs去优化另一个变量 最后优化模型&#xff0c;大致代码如下 optimizer optim.Adam(model.parameters(), lrlr)for inputs in dataloader:outputs model(inputs)u outputs.reshape(1, -1, 1)beta to…

扫地机器人还能创新吗?云鲸给了个Yes

作者 | 辰纹 来源 | 洞见新研社 1996年&#xff0c;瑞典家电巨头伊莱克斯推出全球首款扫地机器人“三叶虫”。 与现在的产品相比&#xff0c;“三叶虫”靠随机碰撞的模式对空间进行清扫&#xff0c;清洁效率很低&#xff0c;市场渗透率也不高&#xff0c;但并不妨碍戴森、iRo…

表单引擎的自定义控件的概念与设计

基本概念 概述 控件的定义&#xff1a;用于展示或者采集数据的表单元素&#xff0c;称为控件,比如&#xff1a;文本框、下拉框、单选按钮、从表等.自定义控件&#xff1a;表单引擎提供的基础控件之外的控件称为自定义控件, 这些控件由开发人员自己定义&#xff0c;比如&#…

更灵活的 serverless framework 配置文件

更灵活的 serverless framework 配置文件 前言 再经过前置教程的部署之后&#xff0c;不知道你有没有注意这样一个问题&#xff0c;就是我们部署的函数名&#xff0c;以及 API网关 的 endpoint&#xff0c;它们的名称和路径都带一个 dev? 这个就是 stage 导致的了&#xff…

美客多选品趋势分析,美客多选品时的注意事项

都知道选品的重要性&#xff0c;美客多这个平台也一样&#xff0c;选品选对了肯定事半功倍&#xff0c;本文介绍了美客多选品趋势分析&#xff0c;美客多选品时的注意事项&#xff0c;一起来了解下吧。、 美客多选品趋势分析 1、墨西哥站&#xff1a;跨境支付高&#xff0c;偏…

ESP32C3 PWM输出

目前对于遥控双发差速小飞机计划采用如下架构&#xff1a; ESP32C3做主控&#xff0c;兼具遥控收发和飞行控制锂电池供电&#xff0c;带电量检测双发&#xff0c;720空心杯电机&#xff0c;55mm桨&#xff0c;带电流检测MPU6050加速度计和陀螺仪预留4个控制信号输出 马达控制要…

(Java)多线程带来的的风险-线程安全 (第一部)

前言&#xff1a;线程安全是整个多线程中&#xff0c;最为复杂的部分&#xff0c;也是最重要的部分。 目录 什么是线程安全问题&#xff1f; 线程不安全的原因 ⁜⁜总结 &#xff1a;线程安全问题的原因 ⁜⁜ 解决方法1 ——加锁 synchronized &#xff08;监视器锁monitor…

算法与设计分析--实验一

蛮力算法的设计与分析&#xff08;暴力&#xff09; 这次是某不知名学院开学课程的第一次实验&#xff0c;一共5道题&#xff0c;来自力扣 第一题.216组合总和*力扣题目链接 第一道题是经典的树型回溯 class Solution { public:vector<vector<int>> combinatio…

红米Note12Turbo解锁BL刷入PixelExperience原生ROM系统详细教程

红米Note12Turbo的兄弟是国外POCO F5 机型&#xff0c;并且该机性价比非常高&#xff0c;国内外销量也还可以&#xff0c;自然不缺第三方ROM适配。目前大家心心念念的原生PixelExperience已成功发布&#xff0c;并且相对来说&#xff0c;适配程度较高&#xff0c;已经达到日用的…

sqlserver union和union all 的区别

1.首先在数据库编辑1-40数字&#xff1b; 2.查询Num<30的数据&#xff0c;查询Num>20 and Num<40的数据&#xff0c;使用union all合并&#xff1b; 发现30-20的数字重复了&#xff0c;可见union all 不去重&#xff1b; 3.查询Num<30的数据&#xff0c;查询Num…

嵌入式Linux驱动开发(同步与互斥专题)(一)

一、内联汇编 1.1、语法 内联汇编实现加法 1.2、同步互斥失败的例子 进程A在读出valid时发现它是1&#xff0c;减1后为0&#xff0c;这时if不成立&#xff1b;但是修改后的值尚未写回内存&#xff1b;假设这时被程序B抢占&#xff0c;程序B读出valid仍为1&#xff0c;减1后为…

Callable、Future和FutureTask

一、Callable 与 Runnable 先说一下java.lang.Runnable吧&#xff0c;它是一个接口&#xff0c;在它里面只声明了一个run()方法&#xff1a; public interface Runnable {public abstract void run(); }由于run()方法返回值为void类型&#xff0c;所以在执行完任务之后无法返…

云数据库知识学习——概述

一、云计算是云数据库兴起的基础 云计算是分布式计算、并行计算、效用计算、网络存储、虚拟化、负载均衡等计算机和网络技术发展融合的产物。云计算是由一系列可以动态升级和被虚拟化的资源组成的&#xff0c;用户无需掌握云计算的技术&#xff0c;只要通过网络就可以访问这些资…

关于近期小程序测试的常见漏洞演示

本章节将为大家介绍一下小程序常见的漏洞的展示案例&#xff0c;包括支付业务逻辑漏洞、任意用户登录漏洞、水平越权漏洞等高危漏洞。 以上小程序测试均获取授权&#xff0c;并且客户均已得到修复(仅供学习&#xff0c;请勿恶意攻击)​ 关于微信小程序如何拦截数据包&#xff…

Nat. Communications Biology2022 | PepNN+: 用于识别多肽结合位点的深度关注模型

论文标题&#xff1a;PepNN: a deep attention model for the identification of peptide binding sites 论文链接&#xff1a;PepNN: a deep attention model for the identification of peptide binding sites | Communications Biology 代码地址&#xff1a;oabdin / PepN…

csp非零段划分

202109-2 非零段划分 计算机软件能力认证考试系统 code&#xff1a; #include<bits/stdc.h> using namespace std; const int N5e59;int a[N];vector<int> v[N];//v[i]存放所有元素值为i的元素的下标 int main() {ios::sync_with_stdio(false);cin.tie(0),cout.…

20230908_python练习_服务端与客户端数据交互

用户可以通过简单操作进行服务端数据交互&#xff0c;通过简单的sql语句直接获取EXCEL表&#xff0c;可以用来作为交互的基础。主要涉及三部分&#xff1a; 1:数据库存储表结构 --日志记录表结构 create table shzc.yytowz_service_title (leixing varchar2(18),ziduan1 v…

C#__多线程之任务和连续任务

/// <summary> /// /// 任务&#xff1a;System.Threading.Tasks&#xff08;异步编程的一种实现方式&#xff09; /// 表应完成某个单元工作。这个工作可以在单独的线程中运行&#xff0c;也可以以同步方式启动一个任务。 /// /// 连续任务&#…