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

题解链接:

栈的拿手好戏!| LeetCode:20. 有效的括号_哔哩哔哩_bilibili

栈的好戏还要继续!| LeetCode:1047. 删除字符串中的所有相邻重复项_哔哩哔哩_bilibili

栈的最后表演! | LeetCode:150. 逆波兰表达式求值_哔哩哔哩_bilibili

20. 有效的括号

思路:最先出现的右括号肯定是由最邻近的最括号进行抵消的,所以记录左括号的应该需要满足后进先出的格式。然后考虑这样几个边界问题:1、右括号为什么不要进栈?(因为右括号进栈无法再出栈,右括号只是起到提取栈内元素的作用) 2、出栈的括号与当前右括号不匹配怎么办,做哪些操作。(当前括号不匹配,则表明这个右括号无法匹配,而括号匹配是不可以越过括号的,所以直接返回false)

其实在最早使用c语言基于数组构建栈的时候,只需要一个尾部指针即可完成构建。所以对于解题减少时间开销,就可以基于所给出的数组,使用静态指针直接在当前数组上作为栈实现解题。给出两种解法)

// 时间复杂度都是O(n),空间复杂度为o(n),时间开销全在构建的额外的辅助Stack的pop、push操作上
class Solution {
    public boolean isValid(String s) {
        // 思路:最先出现的右括号肯定是由最邻近的最括号进行抵消的,所以记录左括号的应该需要满足后进先出的格式
        // 这样几个问题:1、右括号为什么不要进栈? 2、出栈的括号与当前右括号不匹配怎么办,做哪些操作

        // 构建栈进行求解
        // if(s.length() == 0 || s.length() == 1 || s.length()%2 != 0)
        //     return false;
        
        // Stack<Character> stack = new Stack<>();
        // for(int i=0; i<s.length(); i++){
        //     if(s.charAt(i) == '(' || s.charAt(i) == '[' || s.charAt(i) == '{'){
        //         stack.push(s.charAt(i));
        //     }
        //     else{
        //         if(s.charAt(i) == ')' && stack.isEmpty() == false && stack.peek() == '(')   stack.pop();
        //         else if(s.charAt(i) == ']' && stack.isEmpty() == false && stack.peek() == '[')  stack.pop();
        //         else if(s.charAt(i) == '}' && stack.isEmpty() == false && stack.peek() == '{')  stack.pop();
        //         else    return false;
        //     }
        // }
        // if(stack.isEmpty() == true)
        //     return true;
        // return false;

        // 解法二,就是利用给出的数组,结合定义静态栈指针实现计算,本质上就是快慢双指针,时间效率会得到大幅提升
        // 时间最快的还得是通过递归来实现,但需要结合题目来看是否可以使用递归,下面的150就可以
        if(s.length() == 0 || s.length() == 1 || s.length()%2 != 0)
            return false;

        char[] ch = s.toCharArray();
        Map<Character,Character> map = new HashMap<>();
        map.put(')','(');
        map.put(']','[');
        map.put('}','{');

        int j = -1;
        for(int i=0; i<ch.length; i++){
            // 出现右括号了
            if(map.containsKey(ch[i]) == true){
                if(j>=0 && map.get(ch[i]) == ch[j])
                    j--;
                else
                    return false;
            }
            else
                ch[++j] = ch[i];
        }
  

        if(j == -1)
            return true;
        return false;

    }
}

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

思路:相邻的元素抵消,是后进先出思想的使用;此外抵消之后,前部分元素可能与之后的元素继续抵消,也即持续出栈,因此使用栈来解题呼之欲出。另外使用静态指针的方式继续减少时间开销。并且不管在什么操作上,只要是涉及读取元素,首要考虑采用数组。

// 时间复杂度O(n),空间复杂度大于O(n),因为多构建了一个StringBuilder
class Solution {
    public String removeDuplicates(String s) {
        
        // 每一次删除两个,而且是删除的位置是相邻的元素,那么又是采用栈可以很好的解决,
        // 因为返回的结果是字符串,而栈无法直接将字符拼接成字符串进行返回,因此可构建数组实现栈的模拟,而这里的数组可使用StringBuilder来模拟,
        // StringBuilder比StringBuffer速度快很多

        StringBuilder builder = new StringBuilder();
        char[] ch = s.toCharArray();
        int j = -1;
        for(int i=0; i<ch.length; i++){
            if(j >= 0 && ch[i] == ch[j])
                j--;
            else
                ch[++j] = ch[i];
        }

        for(int i=0; i<=j; i++)
            builder.append(ch[i]);
        return builder.toString();

        // 但是使用数组进行数据的读取与比较比基于StringBuilder的读取来的快的多,所以只需要采用StringBuilder作为结果返回的容器即可
        // StringBuilder builder = new StringBuilder();
        // int j = -1;
        // for(int i=0; i<s.length(); i++){
        //     if(j >= 0 && s.charAt(i) == builder.charAt(j))
        //         builder.deleteCharAt(j--);
        //     else
        //         builder.insert(++j, s.charAt(i));
        // }

        // return builder.toString();
    }
}

150. 逆波特兰表达式求值

class Solution {
    public int evalRPN(String[] tokens) {
        
        // 采用静态指针实现基于已有数组模拟栈
        // 本质上可以视作为快慢双指针解题
        // 时间开销大幅减少

        int j = 0;
        for (int i = 0; i < tokens.length; i++) {
            if (tokens[i].equals("+") || tokens[i].equals("-") || tokens[i].equals("*") || tokens[i].equals("/")) {
                int b = Integer.parseInt(tokens[--j]);
                int a = Integer.parseInt(tokens[--j]);

                switch (tokens[i]){
                    case "+": tokens[j++] = Integer.toString(a+b);  break;
                    case "-": tokens[j++] = Integer.toString(a-b);  break;
                    case "*": tokens[j++] = Integer.toString(a*b);  break;
                    case "/": tokens[j++] = Integer.toString(a/b);  break;
                }
            }
            else{
                tokens[j++] = tokens[i];
            }

        }
       return Integer.parseInt(tokens[0]);
        
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值