【思路详解+详细注释】小白都能看懂的力扣算法详解——栈

一 LC20.有效的括号

题目要求:

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

20. 有效的括号 - 力扣(LeetCode)

思路分析:

       本题要求我们找到成对出现的括号,要求括号左右两边两两对应,因此我们不能简单粗暴的直接计算括号的数量,而是要统计括号出现的规律。我们可以考虑从内层一层层寻找成对的括号,由内向外一直到找完。这时我们就可以借助栈来完成。

        我们遍历整个字符串中的字符,如果是左括号就入栈,右括号就出栈,根据栈的特性,出栈的元素一定是最后一个入栈的元素,因此该元素就和右括号构成了“最内层”的括号组。我们验证这两个元素是否匹配,如果不匹配直接返回false,否则则继续遍历。注意当我们遍历结束时,还需要再次验证栈中是否为空(因为我们将左括号存到了栈里,如果存在多个左括号没有匹配的右括号仍然会返回false)。如果栈也为空,说明确认所有元素都已匹配完成,该字符串符合“有效括号”的定义。

完整代码示例:

class Solution {
    public boolean isValid(String s) {
        // 判断字符串数量如果为奇数,则直接返回false
        if(s.length() % 2 == 1 ) {
            return false;
        }
        // 创建一个栈,利用其先进后出的特性,判断对应位置元素是否匹配
        Stack<Character> stack = new Stack<>();
        // 遍历字符串,如果是左括号,则将对应的右括号入栈
         for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if(c == '(') {
                stack.push(')');
            } else if(c == '{') {
                stack.push('}');
            } else if(c == '[') {
                stack.push(']');
            } else{ 
                // 如果是右括号,判断出栈元素是否与该字符相同,不同直接返回false(需要先判空)
                if(stack.isEmpty() || c != stack.pop()) {
                    return false;
                }
            }
         }
        // 遍历结束,检查栈中是否存在元素,不存在则匹配了
        return stack.isEmpty();
    }
}

二 LC155.最小栈

题目要求:

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。

155. 最小栈 - 力扣(LeetCode)

思路分析:

       构建一个栈,实现出栈入栈方法很简单,但是如何能在常数时间内检索到最小元素呢?我们可以借助另一个辅助栈实现,一个栈用于存储正常的元素,另一个栈存储当前的最小元素,每当有新元素入栈时,判断它与辅助栈的栈顶元素的大小,只有它小于原栈顶元素,才会入栈。

完整代码示例:

class MinStack {

    // 主栈存储所有元素
    private Stack<Integer> stack;
    // 辅助栈存储最小值
    private Stack<Integer> minStack;

    // 初始化两个栈
    public MinStack() {
        stack = new Stack<>();
        minStack = new Stack<>();
    }

    // 将元素 val 压入栈中
    public void push(int val) {
        stack.push(val);
        // 维护辅助栈,存储当前的最小值
        if (minStack.isEmpty() || val <= minStack.peek()) {
            minStack.push(val);
        }
    }

    // 弹出栈顶元素
    public void pop() {
        // 如果弹出的元素是最小值,也需要弹出辅助栈的栈顶
        if (stack.peek().equals(minStack.peek())) {
            minStack.pop();
        }
        stack.pop();
    }

    // 获取栈顶元素
    public int top() {
        return stack.peek();
    }

    // 获取栈中的最小值
    public int getMin() {
        return minStack.peek();
    }
}

三 LC394.字符串解码

题目要求:

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

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

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

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

394. 字符串解码 - 力扣(LeetCode)

思路分析:

       这道题用文字解释不太容易理解,可以参考力扣题解https://leetcode.cn/problems/decode-string/solutions/264879/zhan-de-ji-yi-nei-ceng-de-jie-ma-liao-bie-wang-lia/的思路。

        但是该题解只提供了js和go语言版本的代码,这里给出Java版本的。

完整代码示例:

class Solution {
    public String decodeString(String s) {
        Stack<Integer> countStack = new Stack<>(); // 保存重复次数的栈
        Stack<StringBuilder> stringStack = new Stack<>(); // 保存部分字符串的栈
        StringBuilder currentString = new StringBuilder(); // 当前正在处理的字符串
        int k = 0; // 当前的重复次数

        for (char ch : s.toCharArray()) {
            if (Character.isDigit(ch)) {
                // 如果是数字,构建重复次数
                k = k * 10 + (ch - '0');
            } else if (ch == '[') {
                // 将当前的重复次数和字符串压入栈中
                countStack.push(k);
                stringStack.push(currentString);
                // 开始处理新的部分字符串,重置k和currentString
                currentString = new StringBuilder();
                k = 0;
            } else if (ch == ']') {
                // 从栈中弹出重复次数和之前的部分字符串
                int repeatTimes = countStack.pop();
                StringBuilder decodedString = stringStack.pop();
                // 将当前字符串按重复次数拼接到之前的字符串
                for (int i = 0; i < repeatTimes; i++) {
                    decodedString.append(currentString);
                }
                currentString = decodedString; // 更新当前处理的字符串
            } else {
                // 普通字符,直接加入当前字符串
                currentString.append(ch);
            }
        }

        return currentString.toString(); // 返回解码后的字符串
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值