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

99 阅读1分钟

20. 有效的括号

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

有效字符串需满足:

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

image.png

思路-使用栈

推荐使用栈来解决这个问题。
开始动手之前,首先分析有几种不匹配的情况:

  1. 字符串左方向的括号多余了,所以不匹配

image.png 2. 括号没有多余,但是括号的类型没有匹配上

image.png 3. 字符串里右方向的括号多余了,所以不匹配。

image.png

知道这三种不匹配的情况后,我们就可以开始写代码了,流程如下:

  • 遇到(时将)推入栈;
  • 遇到{时将}推入栈;
  • 遇到[时将]推入栈。
  • 一旦遇到要推入的字符是右括号 “),},]”,就先检查栈顶元素是否和要推入的一样,一样就弹出,不一样就return false;
  • 同样,如果遇到右括号并且栈内没有元素,也return false;
  • 循环结束,return true;

代码实现

class Solution {
    public boolean isValid(String s) {
        Deque<Character> deque = new LinkedList<>();
        char[] ch = s.toCharArray();
        for (char c : ch) {
            if (c == '(') {
                deque.push(')');
            } else if (c == '{') {
                deque.push('}');
            } else if (c == '[') {
                deque.push(']');
            } else if (deque.isEmpty() || deque.peek() != c) {
                return false;
            } else {
                deque.pop();
            }
        }
        return deque.isEmpty();
    }
}
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)

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

给出由小写字母组成的字符串 S重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

image.png

思路-栈

  • 按顺序将字符推入栈,如果要推入的字符与栈顶元素相同,则弹出栈顶元素并且不推入当前元素。
  • 当遍历完所有元素之后,栈内剩下的元素就是最终字符串的反序。
  • 从栈中依次取出字符组成字符串再翻转一下得到最终结果。

代码实现

class Solution {
    public String removeDuplicates(String s) {
        Deque<Character> deque = new LinkedList<>();
        char[] ch = s.toCharArray();
        for (char c : ch) {
            if (deque.isEmpty() || c != deque.peek()) {
                deque.push(c);
            } else {
                deque.pop();
            }
        }
        StringBuilder sb = new StringBuilder();
        while (!deque.isEmpty()) {
            sb.append(deque.removeLast());    
        }
        return sb.toString();
    }
}
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)

150. 逆波兰表达式求值

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

image.png

思路

从字符串中依次取出字符推入栈中,如果遇到非数字的字符(运算符号),则弹出栈顶的前两个数字进行运算(运算方法根据遇到的运算符号决定),最后将运算结果推入栈中。

栈顶头位元素位于预算符号后,栈顶第二位元素位于运算符号前;
例如:
栈:4,8,2,1; 遇到的运算符号为'/';
弹出后为:8 / 4 = 2;
之后将 2 推入栈中;
栈:2,2,1

image.png

代码实现

class Solution {
    public int evalRPN(String[] tokens) {
        Deque<Integer> deque = new LinkedList<>();
        for (String s:tokens) {
            if (s.equals("+")) {
                deque.push(deque.pop() + deque.pop());
            } else if (s.equals("-")) {
                deque.push(-deque.pop() + deque.pop());
            } else if (s.equals("/")) {
                int temp1 = deque.pop();
                int temp2 = deque.pop();
                deque.push(temp2/temp1);
            } else if (s.equals("*")) {
                deque.push(deque.pop() * deque.pop());
            } else {
                deque.push(Integer.valueOf(s));
            }
        }
        return deque.pop();
    }
}
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)