Carl代码随想录算法训练营-Day 11-20. 有效的括号、1047. 删除字符串中的所有相邻重复项、150. 逆波兰表达式求值

摘要

算法训练营第11天算法学习的日常记录。今天的题目是leetcode的三道题:20. 有效的括号、1047. 删除字符串中的所有相邻重复项、150. 逆波兰表达式求值。本文从思路分析上阐述了解题步骤,并进行了具体的Java代码实现。

20、有效的括号

LeetCode题目链接

思路分析

这是一道非常经典的栈的题目。我们发现,如果一大堆括号,都是有效括号的话,那么左右括号一定是一一对应的。比如,一对小括号内一定不能出现单个的左中括号,或右大括号。
因此不难想到,当我们读取到左括号('(', '[', '{')时,就将它们压入栈stack。当读取到右括号(')', ']', '}')时,就将stack的栈顶元素弹出。
如果栈为空,那就说明没有左括号与当前右括号匹配。如果不为空,就检查弹出的左括号与当前右括号是否匹配,如果是,就继续这两个过程,如果否,就说明是无效括号。
当所有的字符读取完之后,还要检查栈是否为空,也就是是否有左括号没匹配完。

代码实现

public boolean isValid(String s) {
            Stack<Character> stack = new Stack<>();
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                switch (c) {
                    case '(', '[', '{':
                        stack.push(c);
                        break;
                    default:
                        if (stack.isEmpty()) {
                            return false;
                        }
                        switch (stack.pop()) {
                            case '(':
                                if (c != ')') return false;
                                break;
                            case '[':
                                if (c != ']') return false;
                                break;
                            case '{':
                                if (c != '}') return false;
                                break;
                            default:
                        }
                }
            }
            return stack.isEmpty();
        }

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

LeetCode题目链接

思路分析

这道题要求删除相邻的相同字符。因此不难想到使用栈的特性便于解题。
遍历字符串。
如果栈为空或者当前字符与栈顶元素不同,就将字符压入栈中。
如果当前字符与栈顶元素相同,就将栈顶弹出,并继续遍历下一个字符。

代码实现

思路非常清晰。但在Java中,如果使用Stack类作为栈,我们解这道题的最后还需要使用StringBuilder类来拼接字符串,并且因为栈后进先出的特性,还要让StringBuilder类完成一次反转操作,耗费时间空间。
因此本文选择直接使用StringBuilder类完成栈的操作,相当于用链表实现栈,并且因为只需要操作链表尾部元素,从而时间复杂度较低。

public String removeDuplicates(String s) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < s.length(); i++) {
                if (!sb.isEmpty() && sb.charAt(sb.length() - 1) == s.charAt(i)) {
                    sb.deleteCharAt(sb.length() - 1);
                } else {
                    sb.append(s.charAt(i));
                }
            }
            return sb.toString();
        }

150、逆波兰表达式求值

LeetCode题目链接

思路分析

不难发现,逆波兰表达式的写法与栈的后进先出的特性简直如出一辙,这是因为逆波兰表达式本就是为计算机设计的!
对于一个逆波兰表达式[a,b,+],我们只需要在遍历到数字ab时进行压栈,在遍历到操作服+时,将ab弹出,分别作为+的操作数即可。
那对于复杂一点的逆波兰表达式[c,a,b,+,-],又该如何操作呢?
同样的,遍历到数字,就压栈;遍历到操作符,就弹出两个元素作为操作数,计算的也就是a+b
计算完成后,再将a+b的结果压栈,此时栈中元素为ca+b
遍历到-时,将计算c-(a+b),此时弹出两个元素,依次为a+bc。这就启示我们:先弹出的元素要放到操作符右边,后弹出的元素放到操作符左边。
当所有的字符遍历结束后,栈中剩下的元素就是完全的计算结果了。

代码实现

public int evalRPN(String[] tokens) {
            Stack<Integer> stack = new Stack<>();
            for (String token : tokens) {
                int ans;
                if (token.chars().allMatch(Character::isDigit)) {
                    ans = Integer.parseInt(token);
                } else {
                    ans = cal(stack.pop(), stack.pop(), token);
                }
                stack.push(ans);
            }
            return stack.pop();
        }

        private int cal(int b, int a, String op) {
            return switch (op) {
                case "+" -> a + b;
                case "-" -> a - b;
                case "*" -> a * b;
                case "/" -> a / b;
                default -> throw new IllegalStateException("Unexpected value: " + op);
            };
        }

总结和思考

以上就是今天的算法学习记录,我们通过分析思路和实现代码的方式,解决了这三道题目。希望对大家的算法学习有所帮助,谢谢阅读!

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值