代码随想录算法训练营第十一天| 20. 有效的括号 ,1047. 删除字符串中的所有相邻重复项 ,150. 逆波兰表达式求值

LeetCode 20. 有效的括号

这道题当时上数据结构时老师有讲过,是一道经典的用栈来解决的问题,但我还是没记住要怎么做,所以看了题解思路。解题的关键在于:遇到左括号入栈,遇到右括号出栈,如果不匹配则可能有以下三种情况:1)左括号多余,体现为数组遍历结束后,栈中仍有元素;2)括号类型不匹配,则需要具体情况具体分析啦;3)右括号多余,体现为遇到右括号时,栈中没有元素。代码如下:

class Solution {
    public boolean isValid(String s) {
        String[] ss = s.split("");
        Stack<String> stack = new Stack<>();
        for(int i=0; i<ss.length; i++){
            if(ss[i].equals(")") || ss[i].equals("]") || ss[i].equals("}")){
                // 处理右括号多余的情况
                if(stack.size() == 0) return false;
                String temp = stack.peek(); // 栈顶元素
                System.out.print(temp);
                switch(ss[i]) {
                    case ")":
                        if(!temp.equals("(")) return false; // 括号类型不匹配
                        break;
                    case "]":
                        if(!temp.equals("[")) return false;
                        break;
                    default:
                        if(!temp.equals("{")) return false; 
                }
                // 匹配通过
                stack.pop();
            }else {
                stack.push(ss[i]);
            }
        }
        // 处理左括号多余的情况
        if(stack.size() != 0) return false;
        return true;
    }
}

看了题解代码之后,学会了一个处理小技巧:每次遇到左括号时可以将对应的右括号入栈,这样等遇到右括号时,只需判断当前元素与栈顶元素是否相等即可,代码会少一些,代码如下:

class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for(int i=0; i<s.length(); i++){
            char temp = s.charAt(i);
            switch(temp){
                case '(':
                    stack.push(')');
                    break;
                case '[':
                    stack.push(']');
                    break;
                case '{':
                    stack.push('}');
                    break;
                default:
                    if(stack.size() == 0 || temp != stack.peek()) return false;
                    stack.pop();
            }
        }
        // 处理左括号多余的情况
        if(stack.size() != 0) return false;
        return true;
    }
}

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

想法:判断当前元素与栈顶元素是否相等,若相等,则栈顶元素出栈,若不相等,则当前元素入栈。最后将栈中的元素变为String类型return就好,这里有一个小坑,就是栈是先进后出,但我们return得字符串需要按照原先的顺序,所以拼接的时候要注意一下顺序。代码如下:

class Solution {
    public String removeDuplicates(String s) {
        Stack<Character> stack = new Stack<>();
        for(int i=0; i<s.length(); i++){
            char temp = s.charAt(i);
            if(stack.size() == 0 || temp != stack.peek()) {
                stack.push(temp);
            } else if(temp == stack.peek()){
                stack.pop();
                continue;
            }
        }
        String result = "";
        while(!stack.isEmpty()){
            result = stack.pop() + result;
        }
        return result;
    }
}

题解中提及的双指针解法目前没有看明白,等二刷的时候再仔细学习一下吧。

题外话

实现函数的递归调用需要用到栈,但不是每种语言都支持递归。

递归的实现:每一次的递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,这就是为什么递归可以返回上一层位置的原因。

有一种错误叫栈溢出,即Segmentation fault(当然不是所有的Segmentation fault 都是栈溢出导致的),如果使用了递归就要想想是不是无限递归了。在企业项目开发中,尽量不要使用递归,在项目比较大的时候,由于参数多、全局变量等等,使用递归很容易判断不充分return的条件,非常容易无限递归(或递归层级过深),造成栈溢出错误不好排查。

LeetCode 150. 逆波兰表达式求值

题目还比较简单,关键思路是:遇到数字就入栈,遇到运算符就pop后两个数字进行运算,最后将结果入栈。需要特别处理"-", "/",因为栈先进后出的特性,数字压入栈再出栈,被减数和被除数的位置变了,还要就是String转Integer时用Integer.valueOf函数会比Integer.parseInt更合适,因为后者会抛NumberFormatException异常,代码如下:

class Solution {
    public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<>();
        int num1 = 1;
        int num2 = 1;
        for(int i=0; i<tokens.length; i++){
            if(tokens[i].equals("+") || tokens[i].equals("-")  || tokens[i].equals("*") || tokens[i].equals("/")){
                num1 = stack.pop();
                num2 = stack.pop();
            }
            switch(tokens[i]) {
                case "+":
                    stack.push((num1 + num2));
                    break;
                case "-":
                    stack.push((num2 - num1));
                    break;
                case "*":
                    stack.push((num1 * num2));
                    break;
                case "/":
                    stack.push((num2 / num1));
                    break;
                default:
                    stack.push(Integer.valueOf(tokens[i]));
            }
        }
        return stack.pop();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值