常见“栈“相关题目

news2025/3/9 5:44:57

找往期文章包括但不限于本期文章中不懂的知识点:

个人主页:我要学编程(ಥ_ಥ)-CSDN博客

所属专栏: 优选算法专题

目录

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

844.比较含退格的字符串

227.基本计算器 II

394.字符串解码

946.验证栈序列


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

题目:

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

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

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

示例:

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

提示:

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

思路:这个题目有点类似消消乐这个游戏,这种我们一般都是采用栈的方式来实现。

直接使用栈的方式:遍历字符串,如果栈不为空,且栈顶的元素与当前字符串的元素的值相同,就出栈,否则就进栈。直至遍历完字符串,然后再遍历栈拿到最终的字符序列,最后只需逆置即可。

上面的方式虽然非常简单,但是需要遍历栈拿到字符序列,最后还得去逆置,比较麻烦,我们可以尝试去模拟栈的思想来解决。创建一个StringBuilder对象,当该对象的字符数不为null,且最后一个字符与当前字符串中的元素的值相等时,就删除最后一个字符,否则就加入该对象。最后遍历完成之后,就可以直接返回了。

代码实现:

直接使用栈:

class Solution {
    // 直接使用栈
    public String removeDuplicates(String s) {
        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            // 栈不为空且栈顶元素与当前字符串的元素的值相等,就出栈
            if (!stack.isEmpty() && stack.peek() == c) {
                stack.pop();
            } else {
                stack.push(c);
            }
        }
        StringBuilder builder = new StringBuilder();
        while (!stack.isEmpty()) {
            builder.append(stack.pop());
        }
        return builder.reverse().toString();
    }
}

模拟栈:

class Solution {
    // 模拟栈的方式
    public String removeDuplicates(String s) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            // 与上述栈的处理方式相同
            if (builder.length() != 0 && builder.charAt(builder.length()-1) == c) {
                builder.deleteCharAt(builder.length()-1);
            } else {
                builder.append(c);
            }
        }
        return builder.toString();
    }
}

注意:StringBuilder (StringBuffer) 的 capacity方法 与 length方法 的含义不一样。capacity方法是获取其底层的字符数组的大小(不是有效的元素个数,而是总大小),length方法是获取其字符数组的有效长度。 

844.比较含退格的字符串

题目:

给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 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
  • s 和 t 只含有小写字母以及字符 '#'

思路:本题也是一个简单的模拟题。遍历字符串,遇到 '#',就删除前面的字符即可,最终只需要判断两个字符串经过上述处理之后的结果是否是一致的。

代码实现:

class Solution {
    public boolean backspaceCompare(String s, String t) {
        StringBuilder ss = new StringBuilder();
        StringBuilder tt = new StringBuilder();
        for (int i = 0, j = 0; i < s.length() || j < t.length(); i++, j++) {
            if (i < s.length()) {
                // 遇到 '#' 且 StringBuilder 对象不为空,就出栈
                if (s.charAt(i) == '#') {
                    if (ss.length() != 0) {
                        ss.deleteCharAt(ss.length()-1);
                    }
                } else {
                    ss.append(s.charAt(i));
                }
            }
            
            if (j < t.length()) {
                // 遇到 '#' 且 StringBuilder 对象不为空,就出栈
                if (t.charAt(j) == '#') {
                    if (tt.length() != 0) {
                        tt.deleteCharAt(tt.length()-1);
                    }
                } else {
                    tt.append(t.charAt(j));
                }
            }
        }
        return ss.toString().equals(tt.toString());
    }
}

注意:StringBuilder(StringBuffer) 的 equals 方法并未重写,而是直接继承的Object类的equals方法,比较的是对象的内存地址;而String的equals方法是重写之后的,比较的对象的值。因此这里在比较时,需要先使用 toString方法转换为字符串,再去比较。

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 * 10^5
  • s 由整数和算符 ('+', '-', '*', '/') 组成,中间由一些空格隔开
  • s 表示一个 有效表达式
  • 表达式中的所有整数都是非负整数,且在范围 [0, 2^31 - 1] 内
  • 题目数据保证答案是一个 32-bit 整数

思路:题目就是让我们计算出一段字符串序列的最终值,而这个字符串序列中包含了 +、-、*、/、空格 与 数字。由于在计算字符串序列的值时,乘除运算符的优先级是高于加减的,因此我们可以先将乘除的运算全部先计算出来,最后再去计算出加减的值。那我们就可以先遍历字符串,如果遇到了空格可以直接跳过,如果遇到了数字字符,就拿到完整的数字(可能不是一位数),然后根据前者的运算符是啥,来决定当前数据做什么处理,如果遇到了运算符,就直接记录下来即可。

代码实现:

class Solution {
    public int calculate(String s) {
        int n = s.length(), i = 0;
        char[] strs = s.toCharArray();
        Stack<Integer> stack = new Stack<>();
        char op = '+'; // 初始化为'+'
        while (i < n) {
            // 排除空格的情况
            while (i < n && strs[i] == ' ') { // 避免越界
                i++;
            }
            if (i == n) {
                break;
            }
            // 处理数字
            if (i < n && strs[i] >= '0' && strs[i] <= '9') {
                // 先拿到完整的数字
                int num = 0;
                while (i < n && strs[i] >= '0' && strs[i] <= '9') {
                    num = num * 10 + (strs[i] - '0');
                    i++;
                }
                // 根据运算符的情况,将不同情况的数据入栈
                if (op == '+') { // 加上数据
                    stack.push(num);
                } else if (op == '-') { // 减去数据
                    stack.push(-num);
                } else if (op == '*') { // 让栈顶的数据乘上该数据
                    stack.push(stack.pop() * num);
                } else { // 让栈顶的数据除去该数据
                    stack.push(stack.pop() / num);
                }
                // 处理完上述不需要 i++,因为上述刚好将i+1的位置确认为非数字,但未处理
            } else {
                // 处理运算符
                op = strs[i];
                i++;
            }
        }
        // 将栈中所有元素相加即可
        int ret = 0;
        while (!stack.isEmpty()) {
            ret += stack.pop();
        }
        return ret;
    }
}

394.字符串解码

题目:

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

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

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

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[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] 

思路:本题和表达式求值的思路是类似的,都是先计算出优先级较高的。而这里是需要我们先将括号内的字符串解析出来,然后再去拼接出最终的字符串。内嵌的字符串的优先级是最高的,也是最先需要解析出来的。

代码实现:

class Solution {
    public String decodeString(String s) {
        // 创建一个数字栈、一个字符串栈
        Stack<String> s_stack = new Stack<>();
        Stack<Integer> n_stack = new Stack<>();
        s_stack.push(""); // 避免纯字符前缀无法添加到栈顶元素的末尾
        int n = s.length(), i = 0;
        char[] strs = s.toCharArray();
        while (i < n) {
            if (strs[i] >= '0' && strs[i] <= '9') { // 数字
                int num = 0;
                while (strs[i] >= '0' && strs[i] <= '9') { // 可能不止一位数
                    num = num * 10 + (strs[i] - '0');
                    i++;
                }
                n_stack.push(num); // 数字入栈
            } else if (strs[i] == '[') { // 左括号
                // 字符串入栈
                i++;
                StringBuilder builder = new StringBuilder();
                // 只需要加入字母,避免右括号 与 数字
                while (strs[i] != ']' && strs[i] <= '0' && strs[i] >= '9') {
                    builder.append(strs[i++]);
                }
                s_stack.push(builder.toString());
            } else if (strs[i] == ']') { // 右括号
                // 字符串栈 出栈,数字栈 出栈
                StringBuilder builder = new StringBuilder(s_stack.pop());
                StringBuilder tmp = new StringBuilder(builder);
                int k = n_stack.pop();
                for (int j = 0; j < k-1; j++) {
                    tmp.append(builder);
                }
                // 添加到栈顶元素的末尾
                builder = new StringBuilder(s_stack.pop());
                s_stack.push(builder.append(tmp).toString());
                i++;
            } else { // 纯字符串
                // 拿到字符串
                StringBuilder tmp = new StringBuilder();
                while (i < n && strs[i] >= 'a' && strs[i] <= 'z') {
                    tmp.append(strs[i++]);
                }
                // 直接添加到栈顶元素的末尾
                StringBuilder builder = new StringBuilder(s_stack.pop());
                builder.append(tmp);
                s_stack.push(builder.toString());
            }
        }
        return s_stack.pop().toString();
    }
}

946.验证栈序列

题目:

给定 pushed 和 popped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 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
  • popped 是 pushed 的一个排列

思路:只需要将push序列一直进栈,并同时判断栈顶的元素是否与指向popped序列的指针值是否一致,如果一致的话,就一致出栈,直至栈为空,如果不一致就一直进栈。重复上述过程,直至最终的栈为空,或者指向popped序列的值为空,说明出栈序列是正确的,反之,则是错误的。

代码实现:

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        Stack<Integer> stack = new Stack<>();
        int i = 0, j = 0, n = popped.length;
        while (i < n) {
            stack.push(pushed[i]);
            while (!stack.isEmpty() && stack.peek() == popped[j]) {
                stack.pop();
                j++;
            }
            i++;
        }
        return stack.isEmpty();
    }
}

好啦!本期 常见“栈“相关题目 的刷题之旅 就到此结束啦!我们下一期再一起学习吧!

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

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

相关文章

QT实现有限元软件操作界面

本系列文章致力于实现“手搓有限元&#xff0c;干翻Ansys的目标”&#xff0c;基本框架为前端显示使用QT实现交互&#xff0c;后端计算采用Visual Studio C。 本篇将二维矩形截面梁单元&#xff08;Rect_Beam2D2Node&#xff09;组成的钢结构桥作为案例来展示软件功能。 也可以…

软件工程经济学-日常作业+大作业

目录 一、作业1 作业内容 解答 二、作业2 作业内容 解答 三、作业3 作业内容 解答 四、大作业 作业内容 解答 1.建立层次结构模型 (1)目标层 (2)准则层 (3)方案层 2.构造判断矩阵 (1)准则层判断矩阵 (2)方案层判断矩阵 3.层次单排序及其一致性检验 代码 …

Go学习:Go语言中if、switch、for语句与其他编程语言中相应语句的格式区别

Go语言中的流程控制语句逻辑结构与其他编程语言类似&#xff0c;格式有些不同。Go语言的流程控制中&#xff0c;包括if、switch、for、range、goto等语句&#xff0c;没有while循环。 目录 1. if 语句 2. switch语句 3. for语句 4. range语句 5. goto语句&#xff08;不常用…

14-8C++STL的queue容器

一、queue容器 (1)queue容器的简介 queue为队列容器&#xff0c;“先进先出”的容器 (2)queue对象的构造 queue<T>q; queue<int>que Int;//存放一个int的queue容器 queue<string>queString;//存放一个string的queue容器 (3)queue容器的push()与pop()方…

【B站保姆级视频教程:Jetson配置YOLOv11环境(四)cuda cudnn tensorrt配置】

Jetson配置YOLOv11环境&#xff08;4&#xff09;cuda cudnn tensorrt配置 文章目录 0. 简介1. cuda配置&#xff1a;添加cuda环境变量2. cudnn配置3. TensorRT Python环境配置3.1 系统自带Python环境中的TensorRT配置3.2 Conda 虚拟Python环境中的TensorRT配置 0. 简介 官方镜…

信号模块--simulink操作

位置simulink/sourses 常用的模块 功能&#xff1a;常数模块&#xff0c;提供一个常数 数据设置可以是一维或多维 一维数据设置 多维数据设置&#xff08;例三维数据设置&#xff09; 方波脉冲模块 模块用于按固定间隔生成方波脉冲信号 振幅就是方波的幅度&#xff0c;0到…

强化学习笔记(3)——基于值函数的方法和策略梯度方法

分为两大类方法&#xff1a; 基于值函数的方法&#xff08;Temporal Difference Methods, TD Methods&#xff09; 策略梯度方法&#xff08;Policy Gradient Methods&#xff09;。 二者不同之处&#xff1a; 通过值函数来间接表达隐式的策略&#xff0c;一个是直接迭代优化策…

新年新挑战:如何用LabVIEW开发跨平台应用

新的一年往往伴随着各种新的项目需求&#xff0c;而跨平台应用开发无疑是当前备受瞩目的发展趋势。在众多开发工具中&#xff0c;LabVIEW 以其独特的图形化编程方式和强大的功能&#xff0c;为开发跨平台应用提供了有效的途径。本文将深入探讨如何运用 LabVIEW 开发能够在不同操…

事务04之死锁,锁底层和隔离机制原理

死锁和事务底层原理 文章目录 死锁和事务底层原理一&#xff1a;MySQL中的死锁现象1&#xff1a;何为死锁1.1&#xff1a;死锁的概念1.2&#xff1a;死锁产生的四个必要条件&#xff1a; 2&#xff1a;MySQL的死锁2.1&#xff1a;死锁的触发2.2&#xff1a;MySQL的死锁如何解决…

Golang 并发机制-2:Golang Goroutine 和竞争条件

在今天的软件开发中&#xff0c;我们正在使用并发的概念&#xff0c;它允许一次执行多个任务。在Go编程中&#xff0c;理解Go例程是至关重要的。本文试图详细解释什么是例程&#xff0c;它们有多轻&#xff0c;通过简单地使用“go”关键字创建它们&#xff0c;以及可能出现的竞…

【4Day创客实践入门教程】Day0 创想启程——课程与项目预览

Day0 创想启程——课程与项目预览 目录 Day0 创想启程——课程与项目预览前言学习内容基本的单片机开发技能简单的焊接技能简单的MicroPython程序 后记 Day1 工具箱构建——开发环境的构建Day2 探秘微控制器——单片机与MicroPython初步Day3 实战演练——桌面迷你番茄钟Day4 迈…

洛谷P3372 【模板】线段树 1以及分块

【模板】线段树 1 题目描述 如题&#xff0c;已知一个数列&#xff0c;你需要进行下面两种操作&#xff1a; 将某区间每一个数加上 k k k。求出某区间每一个数的和。 输入格式 第一行包含两个整数 n , m n, m n,m&#xff0c;分别表示该数列数字的个数和操作的总个数。 …

(动态规划基础 打家劫舍)leetcode 198

已知h2和h1&#xff0c;用已知推出未知 推是求答案&#xff0c;回溯是给答案 这里图片给出dfs暴力&#xff0c;再进行记录答案完成记忆化搜索&#xff0c;再转为dp数组 #include<iostream> #include<vector> #include<algorithm> //nums:2,1,1,2 //dp:2,2,…

Python 梯度下降法(四):Adadelta Optimize

文章目录 Python 梯度下降法&#xff08;四&#xff09;&#xff1a;Adadelta Optimize一、数学原理1.1 介绍1.2 实现流程 二、代码实现2.1 函数代码2.2 总代码 三、优缺点3.1 优点3.2 缺点 四、相关链接 Python 梯度下降法&#xff08;四&#xff09;&#xff1a;Adadelta Opt…

旅行的意义:“诗与远方”和在旅途中找寻真我

原文链接&#xff1a;旅行的意义&#xff1a;“诗与远方”和在旅途中找寻真我 困在格子间&#xff0c;心向远方 清晨&#xff0c;闹钟催促&#xff0c;打工人挣扎起床出门。地铁拥挤&#xff0c;工作繁忙&#xff0c;加班成常态&#xff0c;下班时夜幕已深&#xff0c;满心疲惫…

leetcode——将有序数组转化为二叉搜索树(java)

给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡 二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#xff1a;[0,-10,5,null,-3,null,9] 也将被视为正确答…

前端js高级25.1.30

原型&#xff1a;函数的组成结构 通过这个图我们需要知道。 假设我们创建了一个Foo函数。 规则&#xff1a;Function.protoType是函数显示原型。__proto__是隐式对象。 Function、Object、Foo函数的__proto__指向了Function.protoType说明。这三个都依托function函数来创建。…

【后端开发】字节跳动青训营之性能分析工具pprof

性能分析工具pprof 一、测试程序介绍二、pprof工具安装与使用2.1 pprof工具安装2.2 pprof工具使用 资料链接&#xff1a; 项目代码链接实验指南pprof使用指南 一、测试程序介绍 package mainimport ("log""net/http"_ "net/http/pprof" // 自…

云原生(五十二) | DataGrip软件使用

文章目录 DataGrip软件使用 一、DataGrip基本使用 二、软件界面介绍 三、附件文件夹到项目中 四、DataGrip设置 五、SQL执行快捷键 DataGrip软件使用 一、DataGrip基本使用 1. 软件界面介绍 2. 附加文件夹到项目中【重要】 3. DataGrip配置 快捷键使用&#xff1a;C…

FreeRTOS学习 --- 任务调度

开启任务调度器 作用&#xff1a;用于启动任务调度器&#xff0c;任务调度器启动后&#xff0c; FreeRTOS 便会开始进行任务调度 该函数内部实现&#xff0c;如下&#xff1a; 1、创建空闲任务&#xff08;优先级最低&#xff09; 2、如果使能软件定时器&#xff0c;则创建定…