跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

栈的经典算法应用:LeetCode 精选题目解析

通过五个 LeetCode 经典题目,演示了栈数据结构在字符串处理、表达式计算及序列验证中的核心应用。涵盖删除相邻重复项、含退格符字符串比较、基本计算器 II、字符串解码以及验证栈序列。重点讲解了如何利用栈的后进先出特性解决嵌套匹配、临时存储及状态回溯问题,提供了完整的 Java 代码实现与复杂度分析。

性能调优发布于 2026/2/6更新于 2026/7/1952 浏览
栈的经典算法应用:LeetCode 精选题目解析

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

题目描述:

字符串中相邻字符相同,就要删去,删去之后相邻字符相同也要删去。

解题思路:

  • 我们使用栈来存储,从前遍历字符串的字符。
  • 拿到一个字符,就看栈顶元素是否相同,如果相同就出栈,不同就入栈。
  • 注意在看栈顶元素前,要看栈是不是空。
  • 这里可以使用数组来代替栈。

解题代码:

// 时间复杂度:O(n)
// 空间复杂度:O(n)
class Solution {
    public String removeDuplicates(String s) {
        StringBuffer ret = new StringBuffer();
        for (int i = 0; i < s.length(); i++) {
            if (ret.length() > 0 && s.charAt(i) == ret.charAt(ret.length() - 1)) {
                ret.deleteCharAt(ret.length() - 1);
            } else {
                ret.append(s.charAt(i));
            }
        }
        return ret.toString();
    }
}

二、844.比较含退格的字符串

题目描述:

当字符串中是'#'的时候就将前一个字符删去,删去之后再遇到'#'也要删去前一个字符。判断两个字符串按照上面规则运算后,是否相同。

解题思路:

  • 这和上一道题是一道题,只不过判断条件从前一个字符是否相等,变成了当前字符是不是'#'。
  • 我们只需要封装一个方法进行删除就行,最后判断两个字符串调用了方法后是否内容相同即可。

解题代码:

// 时间复杂度:O(n)
// 空间复杂度:O(n)
class Solution {
    public boolean backspaceCompare(String s, String t) {
        return backspace(s).equals(backspace(t));
    }

    // 返回处理#后的结果
     String  {
            ();
         (   ; i < s.length(); i++) {
             (ret.length() >  && s.charAt(i) == ) {
                ret.deleteCharAt(ret.length() - );
            }
             (s.charAt(i) != ) {
                ret.append(s.charAt(i));
            }
        }
         ret.toString();
    }
}
public
backspace
(String s)
StringBuffer
ret
=
new
StringBuffer
for
int
i
=
0
if
0
'#'
1
if
'#'
return

三、227.基本计算器 II

题目描述:

给我们一个字符串,其中只包含加减乘除和数字和空格几种字符。返回按照数学运算,计算后的数字,这个数字不会超过 int 范围。

解题思路:

  • 整体思路:将所有的运算符变成加。
  • 我们只需要将每个数字前面的运算符使用运算符变量记录下来。
  • 当遍历到字符为空格就向后走。
  • 遍历到是运算符,就将运算符变量更新为这个运算符,向后走。
  • 遍历到数字,我们使用变量记录下来,再向后遍历看是不是数字,因为在这道题中 123 这种是三个字符连在一堆表示。
  • 当变量存储完之后,看前面的运算符变量是什么,是减,就将相反数入栈,是加,直接入栈,是乘和除,就拿栈顶元素进行运算后再入栈。
  • 最后将栈中的元素加起来就是结果了。

解题代码:

// 时间复杂度:O(n)
// 空间复杂度:O(n)
class Solution {
    public int calculate(String s) {
        Stack<Integer> stack = new Stack<>();
        char op = '+';
        int i = 0;
        while (i < s.length()) {
            if (s.charAt(i) == ' ') {
                i++;
            } else if (s.charAt(i) >= '0' && s.charAt(i) <= '9') {
                int tmp = 0;
                while (i < s.length() && s.charAt(i) >= '0' && s.charAt(i) <= '9') {
                    tmp = tmp * 10 + (s.charAt(i) - '0');
                    i++;
                }
                if (op == '+') stack.push(tmp);
                if (op == '-') stack.push(-tmp);
                if (op == '*') stack.push(stack.pop() * tmp);
                if (op == '/') stack.push(stack.pop() / tmp);
            } else {
                op = s.charAt(i);
                i++;
            }
        }
        int ret = 0;
        while (!stack.isEmpty()) {
            ret += stack.pop();
        }
        return ret;
    }
}

四、394.字符串解码

题目描述:

中括号中的字符要重复中括号前面的数字倍。数字只会作为倍数出现。

解题思路:

  • 我们遍历字符串会出现四种情况:字母(指不被中括号包含的)、数字、左括号 '['、右括号 ']'。
  • 我们要将数字与数字对应要重复的字符串对应起来,所以我们使用两个栈分别储存数字和字符串。
  • 遇到数字的时候,我们就将数字提取出来,放入数字栈中。使用循环遍历拿到每个数字字符(不用注意越界),加在个位即可。
  • 遇到左括号 '[' 时,我们就将左括号和右括号中包含的字符串(不用注意越界因为一定有']')放入栈顶。
  • 遇到右括号 ']' 时,我们就拿去两个栈的栈顶元素,重复字符串,拼接在现在的栈顶元素后。
  • 遇到字母(指不被中括号包含的)时,拿取这个字符串(此时需要注意越界问题),拼接在现在的栈顶元素后。
  • 因为有拼接在栈顶元素,如果字符串开始时就是字母(指不被中括号包含的),那么会空指针异常,所以在一开始的字符串栈就填入一个空串。

解题代码:

// 时间复杂度:O(n)
// 空间复杂度:O(n)
class Solution {
    public String decodeString(String s) {
        Stack<StringBuffer> stackString = new Stack<>();
        stackString.push(new StringBuffer());
        Stack<Integer> stackInt = new Stack<>();
        int cur = 0;
        while (cur < s.length()) {
            if (s.charAt(cur) >= '0' && s.charAt(cur) <= '9') {
                // 数字
                int tmp = 0;
                while (s.charAt(cur) >= '0' && s.charAt(cur) <= '9') {
                    tmp = tmp * 10 + (s.charAt(cur++) - '0');
                }
                stackInt.push(tmp);
            } else if (s.charAt(cur) == '[') {
                // 左括号
                cur++;
                StringBuffer tmp = new StringBuffer();
                while (s.charAt(cur) >= 'a' && s.charAt(cur) <= 'z') {
                    tmp.append(s.charAt(cur++));
                }
                stackString.push(tmp);
            } else if (s.charAt(cur) == ']') {
                // 右括号
                cur++;
                int k = stackInt.pop();
                StringBuffer tmp = stackString.pop();
                while (k-- != 0) {
                    stackString.peek().append(tmp);
                }
            } else {
                // 字母(指不被中括号包含的)
                while (cur < s.length() && s.charAt(cur) >= 'a' && s.charAt(cur) <= 'z') {
                    stackString.peek().append(s.charAt(cur++));
                }
            }
        }
        return stackString.peek().toString();
    }
}

五、946.验证栈序列

题目描述:

看 popped 数组是不是按照 pushed 数组元素入栈顺序能拿到的顺序。

解题思路:

  • 遍历 pushed 数组,元素入栈,如果 pushed 数组元素与当前 popped 数字的当前下标元素不同,就入栈。
  • pushed 数组元素与当前 popped 数字的当前下标元素相同,就出栈直到栈顶元素与 popped 数字的当前下标元素不同或者栈空为止。
  • 最后如果栈还有元素,那么就返回 false,反之,返回 true。

解题代码:

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        Stack<Integer> stack = new Stack<>();
        int cur = 0; // popped 当前访问的下标
        for (int i = 0; i < pushed.length; i++) {
            if (pushed[i] != popped[cur]) {
                stack.push(pushed[i]);
            } else {
                stack.push(pushed[i]);
                while (!stack.isEmpty() && stack.peek() == popped[cur]) {
                    stack.pop();
                    cur++;
                }
            }
        }
        return stack.isEmpty();
    }
}

目录

  1. 一、1047.删除字符串中的所有相邻重复项
  2. 二、844.比较含退格的字符串
  3. 三、227.基本计算器 II
  4. 四、394.字符串解码
  5. 五、946.验证栈序列
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 移除链表元素与反转链表
  • 模型可解释性在医疗诊断中的应用
  • Whisper 语音识别模型版本详解与官方下载链接
  • Rollup: 下一代 JavaScript 模块打包器
  • Java 多线程:等待唤醒机制与线程池详解
  • 单链表核心操作全实现与深度解析
  • 递归、搜索与回溯算法实战:深入理解暴搜决策树
  • FastAPI 实现 Python 前后端交互:用户登录注册与信息查看
  • MySQL 至 KingbaseES 数据库迁移最佳实践指南
  • AI 编程中的 Skills:概念解析与 Java 方法生成实战
  • Prompt 工程:大语言模型高效使用指南
  • 大模型数据建设:工程化视角与策略实践
  • 基于 DeepFace 和 OpenCV 的实时情绪分析器实现
  • Spring AI Alibaba 深度解析:Java 构建企业级 AI 应用框架指南
  • AIGC 技术全景:原理、应用与未来挑战
  • 一个无人机平台+算法监督平台的离线部署指南
  • 结合腾讯云 HAI 与 DeepSeek 快速搭建个人主页
  • 无人机视觉目标检测数据集 VisDrone 介绍
  • 国内主流大模型 API 调用指南与 Python 实战
  • Flutter 连接以太坊:web3dart 实战与 OpenHarmony 适配指南

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online