【代码训练营】day 11 | 20. 有效的括号 & 1047. 删除字符串中的所有相邻重复项 & 150. 逆波兰表达式求值

91 阅读1分钟

所用代码 java

有效的括号 LeetCode 20

题目链接:有效的括号 LeetCode 20 - 简单

思路

由于题目要求左括号必须以正确的顺序闭合,所以我们可以用栈的思想来存每一个左括号,每次出现一个正确的右括号,就把栈顶的左括号给弹出,若左右括号不匹配则返回false,若字符串遍历完括号也能正确的弹出就返回 true。

public boolean isValid(String s) {
    Stack<Character> stack = new Stack<>();
    char[] c = s.toCharArray();

    for (int i = 0; i < c.length; i++) {
        if (c[i] == '(' || c[i] == '[' || c[i] == '{'){
            stack.push(c[i]);
        }else if (!stack.isEmpty() && stack.peek() == '(' && c[i] == ')'){
            stack.pop();
        }else if (!stack.isEmpty() && stack.peek() == '[' && c[i] == ']'){
            stack.pop();
        }else if (!stack.isEmpty() && stack.peek() == '{' && c[i] == '}'){
            stack.pop();
        }else {
            return false;
        }

    }
    
    return stack.isEmpty();
}

总结

其实java里面String有一个contains方法,可以直接S.contains() "() [] {}"这三种括号,虽然非常的方便,但是效率不高。

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

题目链接:删除字符串中的所有相邻重复项 LeetCode 1047 - 简单

思路

一开始想的是双指针,快慢指针一前一后,遇到相邻的相同字母就继续往两边探索,但是这种方法处理边界比较麻烦。然后再想到用栈的思想,遇到不相同的字母的压入栈,待压入栈元素和栈顶元素相同就弹出栈。试了一下栈不行,栈要改变字母的顺序,输出逆向,应该用队列才行。

public String removeDuplicates(String s) {
    Deque<Character> deque = new ArrayDeque<>();
    char[] c = s.toCharArray();

    for (int i = 0; i < c.length; i++) {
        // 栈为空或者最后一位元素不等于待填充元素,就压入栈
        if (deque.isEmpty() || deque.peekLast() != c[i]){
            deque.offerLast(c[i]);
        }else {
            deque.pollLast();
        }
    }

    StringBuilder sb = new StringBuilder();
    while (!deque.isEmpty()){
        sb.append(deque.pollFirst());
    }

    return sb.toString();
}

总结

其实使用栈也对,只是每个字符添加逆向添加就可以了,添加操作如下:

    String res = "";
    while (!stack.isEmpty()){
        // 保证了每次栈先弹出来的字母在前面
        res = stack.pop() + res;
    }

然后又学习了一下代码随想录上的双指针解法:

public String removeDuplicates(String s) {
    // 双指针
    char[] c = s.toCharArray();
    int fast = 0;
    int slow = 0;
    while (fast < c.length){
        c[slow] = c[fast];
        // 如果slow所指的值和前项相等就退一位
        if (slow > 0 && c[slow] == c[slow-1]){
            slow--;
        }else {
            slow++; // 不想等就正常后移
        }
        // 每次快指针后移一位并赋值给慢指针
        fast++;
    }

    String res = String.valueOf(c);
    return res.substring(0, slow);
    // return new String(c,0,slow);
    // restrn String.valueOf(c,0,slow);
}

明显双指针效率更好!

逆波兰表达式求值 LeetCode 150

题目链接:逆波兰表达式求值 LeetCode 150 - 中等

思路

逆波兰表达式就是后缀表达式。我们可以从左到右把字符串压入栈,遇到符号就弹出两个数进行运算(后弹出的 + - * / 减先弹出的)

public int evalRPN(String[] tokens) {
    Stack<Integer> stack = new Stack<>();
    int firstOut = 0;
    int secondOut = 0;
    int putStackNum = 0;
    for (int i = 0; i < tokens.length; i++) {
        String str = tokens[i];
        // 若是符号,前面就一定有数字
        if (str.equals("+")){
            firstOut = stack.pop();
            secondOut = stack.pop();
            putStackNum = secondOut + firstOut;
            //再把运算出来的结果压入栈
            stack.push(putStackNum);
        }else if (str.equals("-")){
            firstOut = stack.pop();
            secondOut = stack.pop();
            putStackNum = secondOut - firstOut;
            stack.push(putStackNum);
        }else if (str.equals("*")){
            firstOut = stack.pop();
            secondOut = stack.pop();
            putStackNum = secondOut * firstOut;
            stack.push(putStackNum);
        }else if (str.equals("/")){
            firstOut = stack.pop();
            secondOut = stack.pop();
            putStackNum = secondOut / firstOut;
            stack.push(putStackNum);
        }else {
            System.out.println(str);
            // 数字,转为int型并压入栈
            int num = Integer.parseInt(str);
            stack.push(num);
        }
    }
    // 最后存在栈中的就是结果
    return stack.pop();
}

总结

自己写出来感觉非常的冗余,但是能通过,所以又看了下代码随想录发现方法是一样的-_-。所以就留的自己的也好理解