代码随想录LeetCode刷题第八天---------20.有效的括号 1047.删除字符串中的所有相邻重复项150. 逆波兰表达式求值

20有效的括号

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

有效字符串需满足:

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

  • 思路:栈结构非常适合做匹配类的题目,首先就是先要判断什么时候是不匹配的情况。1是括号多了,二就是括号没匹配上。自己测试了一下这种情况就是“(
    [ ) ] ”,这种返回的也是false,也就是说不允许这种交错嵌套,和代码语法的规则类似。用栈解决,自己没想出来,但是很巧妙。
  • 一个一个的遍历括号,正常思路应该是,遍历一个存栈里一个,遇到反括号就对比之后是对应的反括号再出栈,不是对应的反括号就直接匹配失败,也就是字符串无效。
  • 有个小巧思就是入栈的时候直接存上左括号对应的右括号,这样匹配出栈的时候 ,只需要匹配是否相等即可。字符串有效的条件就是,最后栈中的每一个左括号都和右括号恰好的匹配,也就是栈中是空的,并且不在空栈上进一步出栈。

代码:

class Solution {
    public boolean isValid(String s) {
        Stack a = new Stack();
        for(int i=0;i<s.length();i++){//length后面没加括号
            if(s.charAt(i)=='('){
                a.push(')');
            }else if(s.charAt(i)=='['){
                a.push(']');
            }else if(s.charAt(i)=='{'){
                a.push('}');
            }else{
                if(!a.isEmpty()&&s.charAt(i)==')'&&a.peek().equals(')')){
                //直接用==判断出错了,用了equals就好了
                //开始没有判断栈是否为空
                    a.pop();
                }else if(!a.isEmpty()&&s.charAt(i)==']'&&a.peek().equals(']')){
                    a.pop();
                }else if(!a.isEmpty()&&s.charAt(i)=='}'&&a.peek().equals('}')){
                    a.pop();
                }else{
                    return false;
                }
            }
        }
        if(a.isEmpty()){
            return true;
        }else{
            return false;
        }
    }
}


代码随想录判断的比较简洁巧妙,时间也更快,但是不知道这个Deque是干嘛的,作用是什么,(是栈的一种吗?泛型里面是character也不懂)

class Solution {
    public boolean isValid(String s) {
        Deque<Character> deque = new LinkedList<>();
        char ch;
        for (int i = 0; i < s.length(); i++) {
            ch = s.charAt(i);
            //碰到左括号,就把相应的右括号入栈
            if (ch == '(') {
                deque.push(')');
            }else if (ch == '{') {
                deque.push('}');
            }else if (ch == '[') {
                deque.push(']');
            } else if (deque.isEmpty() || deque.peek() != ch) {
                return false;
            }else {//如果是右括号判断是否和栈顶元素匹配
                deque.pop();
            }
        }
        //最后判断栈中元素是否匹配
        return deque.isEmpty();
    }
}

查了,deque是一个双端队列,支持在两端插入和移除元素,可以实现队列,也可以实现栈,deque介绍
Deque有三种用途:
普通队列(一端进另一端出):
Queue queue = new LinkedList()或Deque deque = new LinkedList()
双端队列(两端都可进出)
Deque deque = new LinkedList()
堆栈
Deque deque = new LinkedList()
character是char的引用类型,就是这个队列里只存放char类的元素。

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

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

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

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

  • 自己思路:做了刚刚的括号的题,感觉这个就有点思路了。还是利用栈的思想,首先先逐个存入栈中,如果要存入的下一个元素和当前的顶元素相同,那么不存入,并且把当前栈顶这个元素出栈,不同则入栈,最后栈中的元素就是最终的字符串
  • 遇到的难点:怎么把栈中元素直接转成字符串,发现没有对应的方法,然后查了调研了几个,都不支持,最后用了题解的办法,弹出之后,倒序连接字符串,这样顺序就不会改变了
  • 自己代码:
class Solution {
    public String removeDuplicates(String s) {
        Stack<Character> a = new Stack<>();
        for(int i=0;i<s.length();i++){
            if(a.isEmpty()){
                a.push(s.charAt(i));
            }else{ 
                if(a.peek()==s.charAt(i)){
                a.pop();
                }else{
                    a.push(s.charAt(i));
                }
            }
        }
        //不知道用哪种方法把栈转成字符串:方法一不行
        // StringWriter sw = new StringWriter();
        // PrintWriter pw = new PrintWriter(sw);
        // a.printStackTrace(pw);


        //方法二也不行
        //String sw = ExceptionUtils.getStackTrace(a);
        //栈直接empty方法和isEmpty方法都能用呢,有啥不同呢?

        //题解方法,妙啊,是在很妙a.pop()+tem 和 tem+a.pop()完全不一样
        //直接实现倒序
        String tem="";//注意这里不能是null
        while (!a.empty()){
            tem=a.pop()+tem;
        }
        return tem;
    }
}


题解:

class Solution {
    public String removeDuplicates(String S) {
        //ArrayDeque会比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 str = "";
        //剩余的元素即为不重复的元素
        while (!deque.isEmpty()) {
            str = deque.pop() + str;
        }
        return str;
    }
}

题解习惯用deque不知道为什么
应优先使用此接口而不是遗留 Stack 类。在将双端队列用作堆栈时,元素被推入双端队列的开头并从双端队列开头弹出
deque比stack

150. 逆波兰表达式求值

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
注意:
有效的算符为 ‘+’、‘-’、'’ 和 ‘/’ 。
每个操作数(运算对象)都可以是一个整数或者另一个表达式。
两个整数之间的除法总是 向零截断 。
表达式中不含除零运算。
输入是一个根据逆波兰表示法表示的算术表达式。
答案及所有中间计算结果可以用 32 位 整数表示。
示例 1:
输入:tokens = [“2”,“1”,“+”,“3”,"
"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
逆波兰表达式:
逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中

  • 思路:其实看到这个题也是用栈来做,但是是因为他在这一专题,如果没在这专题的话可能不那么好想,且可以看成这个也是需要匹配的,有匹配的题就常常用栈。现在思路就很清晰,首先就是遍历这个数组,当遇到数字就入栈,当遇到符号就将栈顶的两个元素取出栈,用这个符号来运算,运算结果在存入栈中,依次重复这个过程。
  • 自己代码,Idea通过了,但是力扣没通过,不知道为啥,而且有的idea没报错的语句,力扣都报错
class Solution {
    public int evalRPN(String[] tokens) {
        Deque<Integer> de = new LinkedList<>();
        int re=0;
        for(int i=0;i<tokens.length;i++){
            if(tokens[i]=="+"&&!de.isEmpty()){
               re = de.pop()+de.pop();
                de.push(re);
            }else if(tokens[i]=="-"&&!de.isEmpty()){
                re=de.pop()-de.pop();
                de.push(re);
            }else if(tokens[i]=="*"&&!de.isEmpty()){
                re=de.pop()*de.pop();
                de.push(re);
            }else if(tokens[i]=="/"&&!de.isEmpty()){
                re=de.pop()/de.pop();
                de.push(re);
            }else{
                de.push(Integer.parseInt(tokens[i]));
            }
        }
        return re;
    }
}
//开始是这个栈中存放那种数据类型才好,就迷茫了,直接int也报错,后来就变成String类型的,不知道为什么下面这个都是错的
               // String a = de.pop();
                // String b = de.pop();
                // int re=de.pop()+de.pop();
//                 int a =Integer.parseInt(de.pop());
//                 int b =Integer.parseInt(de.pop());这样都报错 不知道为啥

1.上面的奇怪的错:把==换成equals就不报错了(LeetCode内置jdk问题,不能用双等号判断字符串相等)
2.re没啥用,每次都是重新计算完的值,可以直接赋值进去,返回栈中计算出来的最后一个被压入栈的值,和刚刚的返回re是一样的原理,re的最后计算出来的,是最后一个计算结果,然后把它压入栈中。
3.减法和除法要做一个操作,要不然顺序会有问题,变成后一个除前一个了。

  • 自己正确代码:
class Solution {
    public int evalRPN(String[] tokens) {
        Deque<Integer> de = new LinkedList<>();
        int re1=0,re2=0;
        for(int i=0;i<tokens.length;i++){
            if(tokens[i].equals("+")&&!de.isEmpty()){//把==换成了equals之后就不报错了  
                de.push(de.pop()+de.pop());
            }else if(tokens[i].equals("-")&&!de.isEmpty()){
                 re1=de.pop();  re2= de.pop();//减法和除法的顺序需要考虑
                de.push(re2-re1);
            }else if(tokens[i].equals("*")&&!de.isEmpty()){
                de.push(de.pop()*de.pop());
            }else if(tokens[i].equals("/")&&!de.isEmpty()){
                re1=de.pop();  re2= de.pop();
                de.push(re2/re1);
            }else{
                de.push(Integer.parseInt(tokens[i]));
            }
        }
        return de.pop();//返回栈中计算出来的最后一个被压入栈的值,和刚刚的返回re是一样的原理,re的最后计算出来的,也是最后一个计算结果
    }
}

  • 代码随想录代码,减法的处理很巧妙,除法和咱一样
class Solution {
    public int evalRPN(String[] tokens) {
        Deque<Integer> stack = new LinkedList();
        for (String s : tokens) {
            if ("+".equals(s)) {      
                stack.push(stack.pop() + stack.pop());     
            } else if ("-".equals(s)) {
                stack.push(-stack.pop() + stack.pop());
            } else if ("*".equals(s)) {
                stack.push(stack.pop() * stack.pop());
            } else if ("/".equals(s)) {
                int temp1 = stack.pop();
                int temp2 = stack.pop();
                stack.push(temp2 / temp1);
            } else {
                stack.push(Integer.valueOf(s));
            }
        }
        return stack.pop();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值