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

系列文章目录



20. 有效的括号

(1)不匹配的情况分为三类:①多了左括号,②多了右括号,③左右括号不匹配。
(2)每当遇到了左括号,就把对应的右括号(方便后面比较)加入栈内(用栈就可以保证后进去的可以先进行匹配,符合对称逻辑)。如果遇到了右括号,那么就与栈内的元素进行比较。最终出现的情况:遍历完了栈还有元素(多左),还没遍历完栈已经空了(多右),遍历元素与栈顶元素不相等(左右不匹配)。

利用栈对称匹配

开头可以先对字符串长度进行判断,因为如果长度不是偶数,那么一定是不匹配的括号。

import java.util.Stack;

//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public boolean isValid(String s) {
        if (s.length() % 2 != 0) {// 如果s的长度为奇数,一定不符合要求
            return false;
        }
        Stack<Character> st = new Stack<>();
        char ch;
        for (int i = 0; i < s.length(); i++) {
            ch = s.charAt(i);
            if (ch == '(') {
                st.push(')');
            } else if (s.charAt(i) == '{') {
                st.push('}');
            } else if (s.charAt(i) == '[') {
                st.push(']');
            } else if (st.isEmpty() || st.peek() != ch) {
                //①:遍历字符串匹配的过程中,栈空了,说明多了右括号
                //②遍历字符串匹配的过程中,发现栈里没有我们要匹配的字符。即左右括号不匹配
                return false;
            } else {
                st.pop();
            }
        }
        //最后判断栈中元素是否匹配,如果不为空,说明多了左括号
        return st.isEmpty();
    }
}
//leetcode submit region end(Prohibit modification and deletion)

将栈中元素弹出与判断栈顶元素是否匹配分开,比较耗时(2ms):

 else if (st.isEmpty() || /*st.pop()*/st.peek() != ch) {
                //①:遍历字符串匹配的过程中,栈空了,说明多了右括号
                //②遍历字符串匹配的过程中,发现栈里没有我们要匹配的字符。即左右括号不匹配
                return false;
            } else {
                st.pop();
            }

若将栈中元素弹出与判断栈顶元素是否匹配放一起,比较节省时间(1ms):

else if (st.isEmpty() || st.pop() != ch) {
                //①:遍历字符串匹配的过程中,栈空了,说明多了右括号
                //②遍历字符串匹配的过程中,发现栈里没有我们要匹配的字符。即左右括号不匹配
                return false;
            }

在这里插入图片描述


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

①使用 Deque 作为堆栈(最慢)

(1)Deque是双端队列,两端都可以进出。Deque堆栈操作方法:push()、pop()、peek()
push():将元素推送到由此deque表示的堆栈(换句话说,在此deque的头部),如果当前没有可用空间,则抛出IllegalStateException异常。
此方法相当于addFirst()
pop():从这个deque表示的堆栈中弹出一个元素。 换句话说,删除并返回此deque的第一个元素。
peek():检索但不删除由此deque表示的队列的头部(换句话说,该deque的第一个元素),如果此deque为空,则返回null
(2)基本数据类型转String类型,只需将基本数据类型的值+“”。
(3)加入栈的条件:deque.isEmpty() || deque.peek() != ch,①栈为空。②当前元素不等于栈顶元素。

import java.util.ArrayDeque;

//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public String removeDuplicates(String s) {
        //ArrayDeque会比LinkedList在除了删除元素这一点外会快一点
        //参考:https://stackoverflow.com/questions/6163166/why-is-arraydeque-better-than-linkedlist
        ArrayDeque<Character> deque = new ArrayDeque<>();
        char ch;
        for (int i = 0; i < s.length(); i++) {
            ch = s.charAt(i);
            if (deque.isEmpty() || deque.peek() != ch) {
                deque.push(ch);
            } else {
                deque.pop();
            }
        }
        //基本数据类型转String类型,只需将基本数据类型的值+""。
        String str = "";
        while (!deque.isEmpty()) {
            str = deque.pop() + str;//字符串拼接的同时实现反转
        }
        return str;
    }

}
//leetcode submit region end(Prohibit modification and deletion)

在这里插入图片描述

②双指针法(使用快慢指针)比用栈快很多(第一快)

class Solution {
    public String removeDuplicates(String s) {
        char[] ch = s.toCharArray();
        int fast = 0;
        int slow = 0;
        for (fast = 0; fast < ch.length; fast++) {
        //while(fast <ch.length()){
            // 直接用fast指针所指向的元素的值覆盖slow指针的值
            ch[slow] = ch[fast];

            // 遇到前后相同值的,就跳过,即slow指针后退一步,下次循环就可以直接被覆盖掉了
                //此时为slow-1,即指向第一个重复的元素,在下一次循环中,
                // 由于fast指向两个重复项的后一个元素,就将该元素赋值给第一个重复的元素的位置即slow-1。
            if (slow > 0 && ch[slow] == ch[slow - 1]) {
                slow--;
            } else {
                slow++;
            }
            //fast++;//与while配合使用
        }
        return new String(ch,0,slow);
    }
}

在这里插入图片描述

③直接用StringBuilder当栈,省去了栈还要转为字符串的操作。(第二快)

class Solution {
    public String removeDuplicates(String s) {
        StringBuilder res = new StringBuilder();
        // top为 res 的长度
        int top;
        char ch;
        for (int i = 0; i < s.length(); i++) {
            ch=s.charAt(i);
            top=res.length();
            if(res.length()==0||res.charAt(top-1)!=ch){
                res.append(ch);
            }else {
                res.delete(top-1,top);
                top--;
            }
        }
        return res.toString();
    }
}

在这里插入图片描述


150. 逆波兰表达式求值

注:(1)基本数据类型转String类型:①将基本类型的值+"";②调用toString方法;③调用StringvalueOf方法。
String类型转基本数据类型:①通过基本类型的包装类调用parseXX方法;②调用基本数据类型的包装类的valueOf方法。
(2)减法和除法有先后顺序,故需用临时变量存下两个出栈的值,用后出栈的数-/先出栈的数。

使用Deque作为堆栈

import java.util.Deque;
import java.util.LinkedList;

//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public int evalRPN(String[] tokens) {
        Deque<Integer> stack = new LinkedList<>();
        String ch;
        int number1;
        int number2;
        for (int i = 0; i < tokens.length; i++) {
            ch = tokens[i];
            if ("+".equals(ch)) {
                stack.push(stack.pop() + stack.pop());
            } else if ("-".equals(ch)) {
                number1=stack.pop();
                number2=stack.pop();
                stack.push(number2 - number1);
            } else if ("*".equals(ch)) {
                stack.push(stack.pop() * stack.pop());
            } else if ("/".equals(ch)) {
                number1=stack.pop();
                number2=stack.pop();
                stack.push(number2 / number1);
            }else {
                //stack.push(Integer.parseInt(ch));
                stack.push(Integer.valueOf(ch));
            }
        }
        return stack.pop();
    }
}
//leetcode submit region end(Prohibit modification and deletion)

在这里插入图片描述


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值