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

100 阅读4分钟

20. 有效的括号

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

  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。
  • 每个右括号都有一个对应的相同类型的左括号。
  • s 仅由括号 '()[]{}' 组成

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

思路

利用栈 后进先出 的特点进行括号匹配的判断。

  • 遍历字符串 s.
  • 如果遇到左括号,直接入栈,
  • 如果遇到右括号,
    • 判断当前栈是否为空,
    • 如果栈空,意味着没有相应的左括号与当前的右括号匹配,当前字符串无效,返回 false
    • 否则,判断当前栈顶元素括号类型是否与当前右括号类型相同,
      • 若不同,匹配失败,括号无效,返回 false
      • 否则,则将栈顶元素出栈,继续循环。
  • 循环结束后,所有右括号都有对应顺序的左括号匹配,判断当前栈是否为空,
    • 若栈不空,这意味着有多余的左括号存在,括号无效,返回 false
    • 若栈空,这意味着字符串的所有括号一一对应,括号有效,返回 true

代码

class Solution {
    public boolean isValid(String s) {

        Deque<Character> stack = new LinkedList<>();

        for(int i=0;i<s.length();i++){
            if(s.charAt(i)=='('||s.charAt(i)=='['||s.charAt(i)=='{'){
                stack.push(s.charAt(i));
                continue;
            }

            if(stack.isEmpty()){
                return false;
            }

            if(stack.pop()!=match(s.charAt(i))){
                return false;
            }
        }

        return stack.isEmpty() ? true :false;
    }

     private char match(char bracket){
        char res=0;
        switch(bracket){
            case ')':{
                res='(';
                break;
            }
            case '}':{
                res='{';
                break;
            }
            case ']':{
                res='[';
                break;
            }
        }
        return res;
    }
}

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

给出由小写字母组成的字符串 S重复项删除操作会选择两个相邻且相同的字母,并删除它们。 在 S 上反复执行重复项删除操作,直到无法继续删除。 在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

1047. 删除字符串中的所有相邻重复项 - 力扣(Leetcode)

思路

要判断重复项,就要将当前字符与对之前遍历的字符逆序进行判断,需要用到栈的 后进先出 的特点。

  • 遍历字符串 s,
    • 如果当前栈为空或者栈不空,但是栈顶元素与当前元素不相同,这意味着当前元素与它相邻的元素不重复,将当前元素入栈
    • 上述条件不满足,意味着当前元素与相邻元素重复,不断取出栈顶元素与当前元素比较,如果重复,栈顶元素出栈,并重复这种比较,直到栈空,或者栈顶元素与当前元素不相同为止。
  • 遍历完成后,将栈的元素全部出栈,此时得到的字符序列是逆序的。
  • 将字符序列进行反转,返回结果。

代码

class Solution {
    public String removeDuplicates(String s) {
        Deque<Character> stack = new LinkedList<>();

        for(int i=0;i<s.length();i++){
            if(stack.isEmpty()||stack.peek()!=s.charAt(i)){
                stack.push(s.charAt(i));
                continue;
            }

            while(!stack.isEmpty()&&stack.peek()==s.charAt(i)){
                stack.pop();
            }
        }

        StringBuilder sb = new StringBuilder();
        while(!stack.isEmpty()){
            sb.append(stack.pop());
        }

        return sb.reverse().toString();
    }
}

150. 逆波兰表达式求值

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。 请你计算该表达式。返回一个表示表达式值的整数。 注意:

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

150. 逆波兰表达式求值 - 力扣(Leetcode)

思路

逆波兰表达式的特点是操作数在前,运算符在后,因此,遍历逆波兰表达式时,遇到运算符时,再向前找刚刚遍历的 2 个操作数,同样需要用到栈的 后进先出 的特点。
根据这个特点,遇到运算符时,栈顶元素是这个运算操作的第二个操作数 ,这一点在除法运算中很重要。
算法如下:

  • 遍历逆波兰表达式的数组 tokens
    • 如果当前元素不是运算符,即当前元素表示整数,则将其转换成整型并入栈;
    • 否则,从栈顶依次取出第二个操作数和第一个操作数 ,进行运算,运算格式是 : 结果 = 第一个操作数 运算符 第二个操作数
    • 将运算结果压入栈中,作为之后运算的操作数。
  • 遍历结束后,栈顶元素就是这个表达式的运算结果,取出栈顶元素并返回。

代码

class Solution {
    public int evalRPN(String[] tokens) {

        Deque<Integer> stack = new LinkedList<>();
        int firstNum,secondNum,res;

        for(int i=0;i<tokens.length;i++){
            if(!isOperations(tokens[i])){
                // 不是运算符
                // tokens[i] 是 整数
                stack.push(Integer.valueOf(tokens[i]));
                continue;
            }

            // tokens[i] 是 运算符
            secondNum = stack.pop();
            firstNum = stack.pop();

            // 计算
            if("+".equals(tokens[i])){
                res = firstNum + secondNum;
            }else if("-".equals(tokens[i])){
                res = firstNum - secondNum;
            }else if("*".equals(tokens[i])){
                res = firstNum * secondNum;
            }else{
                res =firstNum / secondNum;
            }

            // 结果压入栈
            stack.push(res);
        }

        return stack.peek();
    }

    private boolean isOperations(String symbol){
        if("+".equals(symbol)||"-".equals(symbol)||
        "*".equals(symbol)||"/".equals(symbol)){
            return true;
        }else{
            return false;
        }
    }
}