算法题(栈)

一、题目

1、字符串解码(LC 394)

2、最小栈(LC 155)

3、有效的括号(LC 20)

二、题解

1、字符串解码(LC 394)

(1)分析

这道题需要把带方括号和数字的编码字符串进行解码,比如把 3[a] 变成 aaa,这种带有嵌套结构适合用栈来解决,因为遇到括号就要回退到上一层处理,刚好符合栈先进后出的特点。整体思路,用两个栈分别保存数字和字符串,再用一个可变字符串实时保存当前正在拼接的内容。

遍历字符串里的每一个字符时,会遇到四种情况:数字、左括号、右括号、普通字母。如果遇到数字,不能直接保存,因为数字可能是多位数,所以要通过计算把字符转成真正的整数。如果遇到左括号,就说明要进入嵌套了,这时候把当前记录的数字和字符串分别压入对应的栈中,然后重置数字和当前字符串,准备处理括号里的内容。

当遇到右括号时,就代表当前层级的字符串结束了,需要把它按照之前保存的数字重复多次。这时候从数字栈取出要重复的次数,把当前字符串复制对应次数,再从字符串栈取出上一层的内容,把两者拼接起来,继续向上一层返回。如果只是普通字母,直接追加到当前字符串后面就可以,最后返回 res 字符串即可。

(2)解答
java 复制代码
class Solution {

/*
遇到的字符可能是 "[","]",数字,字母;
数字后面一定有左括号 "["
遇到 "[" --- 数字放入数字栈、字符串放入字符串栈
遇到 "]" --- 取出数字,复制当前字符,再取出字符栈中的字符拼接当前字符
*/
    public String decodeString(String s) {

        Deque<Integer> stack_num = new ArrayDeque<>();  //存放数字的栈
        Deque<String> stack_str = new ArrayDeque<>();  //存放字符串的栈
        StringBuilder res = new StringBuilder();
        int num = 0;                                //num用来计数

        for(char ch : s.toCharArray()){
            if(ch >='0' && ch <='9'){       //遇到数字字符,计算数字
                num = ch - '0' + num * 10;

            }else if(ch == '['){             //遇到 "["
                stack_num.push(num);            //把数字存放在数字栈
                stack_str.push(res.toString());  //把字符串存放在字符串栈
                num = 0;                        
                res = new StringBuilder();
                
            }else if(ch == ']'){              //遇到 "]"
                Integer count = stack_num.pop();    //取出数字栈的栈顶数字
                StringBuilder temp = new StringBuilder();
                for(int i = 0; i < count; i++){       //根据数字复制字符串
                    temp.append(res);
                }
                res = new StringBuilder(stack_str.pop() + temp); //与字符栈栈顶元素拼接
            }else{               //ch为字母
            res.append(ch);
            }
        }
        return res.toString();
        
    }
}

2、最小栈(LC 155)

(1)分析

这道题要求实现一个栈,同时能在常数时间内获取栈中的最小元素,普通的栈做不到这一点,所以需要改造一下栈的存储结构。不让栈里只保存单个数值,而是保存一个数组,数组里包含两个值,一个是当前入栈的元素本身,另一个是从栈底到当前位置的最小值。

为了避免判断栈空的麻烦,可以在初始化的时候直接放入一个哨兵元素作为栈底,把最小值设为整数最大值,这样后续操作就不用处理边界问题。每次新元素入栈时,最小值都由当前元素和栈顶的最小值比较得出,保证每一个栈位都记录着截至自己位置的最小值。

如此,获取最小值,直接取栈顶数组里记录的最小值即可。出栈、取栈顶的操作和普通栈一样,只是读取数组对应位置的值。此时就实现了正常栈功能和获取最小元素的功能,时间复杂度为O(1)。

(2)解答
java 复制代码
class MinStack {
    private final Deque<int[]> stack = new ArrayDeque<>();
    public MinStack() {
        stack.push(new int[]{0, Integer.MAX_VALUE});  //哨兵栈底
    }
    
    public void push(int val) {
        stack.push(new int[]{val, Math.min(val, getMin())});
    }
    
    public void pop() {
        stack.pop();
    }
    
    public int top() {
        return stack.peek()[0];   //stack.peek()得到的是数组,[0]表示第一个元素val值
    }
    
    public int getMin() { 
        return stack.peek()[1];   //[1]表示数组第二个元素,草拟稿栈底到当前的最小值
    }
}
//栈中的数组,后一个元素指的是是什么---从栈底到当前位置的最小值

*/
/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(val);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

3、有效的括号(LC 20)

(1)分析

判断一个括号字符串是否有效,核心就是左括号必须按顺序闭合,不能交叉,也不能缺少。可以用栈保存所有左括号,再用哈希表存储左右括号的对应关系,方便匹配。

如果字符串长度是奇数,那一定不可能匹配成功,直接返回 false。然后建立左括号到右括号的映射关系,让后续查找更方便。遍历字符串时,遇到左括号就直接压入栈中,遇到右括号就进行匹配检查。

如果遇到右括号时栈已经是空的,说明没有对应的左括号,无效。如果栈不为空,就取出栈顶的左括号,看它对应的右括号和当前字符是否一致,不一致就说明括号不匹配。遍历完成后,如果栈收空的,说明全部匹配了,如果栈不为空,说明字符串无效。

(2)解答
java 复制代码
class Solution {
    public boolean isValid(String s) {
        if(s.length() % 2 != 0){return false;}  //字符数为奇数,不符合
        HashMap<Character, Character> map = new HashMap<>();
        map.put('(',')');
        map.put('{','}');
        map.put('[',']');
        char[] chs = s.toCharArray();
        Deque<Character> stack = new ArrayDeque<>();
        for(char ch : chs){
            if(map.containsKey(ch)){  //ch是左括号,入栈
                stack.push(ch);
            }else{
                if(stack.isEmpty()){return false;}  //栈为空,返回false
                char ch1 = stack.pop();
                if(map.get(ch1) != ch){     //ch是右括号,查询与栈中括号是否匹配
                    return false;
                }
            }
        }
        return stack.isEmpty();
    }
}
//左括号入栈,右括号消除
相关推荐
通信小呆呆1 小时前
基于 ADMM-MFOCUSS 的捷变频雷达扩展目标稀疏重构原理
算法·重构·信息与通信·信号处理·雷达
橙淮1 小时前
Java数组与链表:特性对比与应用场景
数据结构·算法
炽烈小老头1 小时前
【每天学习一点算法 2026/05/15】被围绕的区域
学习·算法·深度优先
芜湖xin1 小时前
【题解-洛谷】P1012 [NOIP 1998 提高组] 拼数
算法·贪心
xiaoxiaoxiaolll2 小时前
金属结构疲劳寿命预测与健康监测技术
人工智能·算法·机器学习
故事和你912 小时前
洛谷-【图论2-1】树4
开发语言·数据结构·c++·算法·动态规划·图论
故事和你912 小时前
洛谷-【图论2-1】树1
开发语言·数据结构·c++·算法·深度优先·动态规划·图论
敲代码的嘎仔3 小时前
力扣高频SQL基础50题详解
开发语言·数据库·笔记·sql·算法·leetcode·后端开发
小虎牙0073 小时前
面试被问复杂度总懵?这篇指南帮你彻底搞清
算法