算法学习第九天| 力扣 20. 有效的括号 1047. 删除字符串中的所有相邻重复项 150. 逆波兰表达式求值

昨天用栈实现队列,队列实现栈,那今天就是栈的经典应用了


昨天学习了栈和队列的相关知识,并用栈实现队列,队列实现栈,那今天就是栈的经典应用了。在今天,我用了三道题来加强对栈的认识,这三道题都是非常经典的。同时,在做题的时候我们也要总结遇到怎么的题型,要求才可以使用栈来解决,一般来说,只要有关对称和匹配的题目,我们都可以考虑用栈来尝试答题。

相关题目:
● 20. 有效的括号:https://leetcode.cn/problems/valid-parentheses/
● 1047. 删除字符串中的所有相邻重复项:https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string/
● 150. 逆波兰表达式求值:https://leetcode.cn/problems/evaluate-reverse-polish-notation/

关于20. 有效的括号

题目描述:
● 给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串,判断字符串是否有效。
● 有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
● 示例 1: 输入: “()” 输出: true
● 示例 2: 输入: “()[]{}” 输出: true
● 示例 3: 输入: “(]” 输出: false
● 示例 4: 输入: “([)]” 输出: false
● 示例 5: 输入: “{[]}” 输出: true

该题的思路:
● 遇到匹配类型的题目,我们就要想到用栈解决,题目要求判断括号是否匹配,那我们就可以将括号一个一个压入栈,并进行判断是否匹配
● 即遍历字符串,将取出的字符进行判断入栈,这里有一个巧妙的方式
● 即如果当前遍历的字符是( { [ 中的一个,则将对应匹配的符号) } ]压入栈
● 若不是( { [ 中的一个,则将当前字符和栈顶元素进行比较,相同则弹出栈顶元素,进行下一轮比较,不同直接return false即可
● 若可以顺利遍历完,则判断栈是否为空,空return true,不空return false,目的是排除有多余括号的情况,例如:({[]}}中第一个 ( 多余,({[]}))中最后一个 )多余
在这里插入图片描述
代码实现

class Solution {
    public boolean isValid(String s) {
        //使用一个栈存放遍历过的符号
        Stack<Character> characterStack = new Stack<>();
        char aChar;

        //循环遍历字符串,临时放到aChar进行比较操作
        for (int i = 0; i < s.length(); i++) {
            aChar = s.charAt(i);

            //进行比较,若当前字符是( { [ 中的一个,则将对应匹配的符号) } ]压入栈
            //这样有利于前后匹配,只要不是( { [中的一个,我们只需要将当前字符aChar与栈顶元素比较是不是相同即可
            if (aChar == '(') {
                characterStack.push(')');
            } else if (aChar == '{') {
                characterStack.push('}');
            } else if (aChar == '[') {
                characterStack.push(']');
            } else {
                //若不是( { [中的一个,并且当前栈为空,则一定是错的,比如字符串 "]{()}"
                if (characterStack.isEmpty()) {
                    return false;
                }
                //若不是( { [中的一个,且当前栈不为空,则进行比较,若相同,则将栈顶元素弹出
                //若不同,则直接返回false即可
                if (characterStack.peek() != aChar) {
                    return false;
                } else {
                    characterStack.pop();
                }
            }
        }
        //最后判断栈是否为空,空才是正确的
        if (characterStack.isEmpty()) {
            return true;
        } else {
            return false;
        }
    }
}

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

题目描述:
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例:
● 输入:“abbaca”
● 输出:“ca”
● 解释:例如,在 “abbaca” 中,我们可以删除 “bb” 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 “aaca”,其中又只有 “aa” 可以执行重复项删除操作,所以最后的字符串为 “ca”。

该题的思路:
● 对于该题的理解需要好好理清楚,是要删除两个相邻且相同的字母,而不是删除连续相同的字母
● 若输入abbaca,则应输出ca
● 若输入abbbaca,则应输出abaca
● 只会同时消除相邻的bb,还剩下一个b是无法消除的
● 方式一:定义一个栈,遍历字符串,判断相邻的两个元素是否相等,若当前元素和栈顶元素相同,则弹出栈顶元素,进行下一轮的循环,此时i也会+1,所以可以看作同时消除了两个元素,最后栈里留下来的元素,再反转一下即为答案。
● 方式二:也可以定义一个StringBuffer当作栈来进行操作,同时定义一个top指针标记当前的头元素,其他的思想和步骤与方式一相同
在这里插入图片描述
代码实现

class Solution {
    public String removeDuplicates(String s) {
        //定义一个栈存放字符
        Stack<Character> stack = new Stack<>();
        char charAt;

        //遍历字符串的每个字符,判断相邻的两个元素是否相等
        for (int i = 0; i < s.length(); i++) {
            charAt = s.charAt(i);
            //如果栈为空或者当前元素和栈顶元素不相等,则push
            if (stack.size() == 0 || charAt != stack.peek()) {
                stack.push(charAt);
            } else {
                //否则就弹出栈顶元素
                stack.pop();
            }
        }
        //构建返回的字符串,反转一下栈的元素
        String str = "";
        while (!stack.isEmpty()) {
            str = stack.pop() + str;
        }

        return str;

    }
}

关于150. 逆波兰表达式求值

题目描述:
● 根据 逆波兰表示法,求表达式的值。
● 有效的运算符包括 + , - , * , / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
● 说明:整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
● 示例 1:输入: [“2”, “1”, “+”, “3”, " * "] 输出: 9
● 解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
● 示例 2:输入: [“4”, “13”, “5”, “/”, “+”] 输出: 6
● 解释: 该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

该题的思路
● 了解到逆波兰表达式之后,可以判断出这也是用栈解决的经典问题,解题的步骤思想也是比较简单
● 遇到数字则将其压入栈内,遇到运算符,则取出栈内的两个元素,并和对应的运算符运算,将结果再次压入栈内
● 最后栈内剩下的数字即为要求的值
在这里插入图片描述
代码实现

class Solution {
    public int evalRPN(String[] tokens) {
        //使用LinkedList模仿栈
        Deque<Integer> deque = new LinkedList<>();

        //遍历,遇到数字就push进去,遇到运算符就取出数字进行运算
        for (String token : tokens) {
            if (token.equals("+")) {
                deque.push(deque.pop() + deque.pop());
            } else if (token.equals("-")) {
                //减法需要特殊处理,注意顺序
                deque.push(-deque.pop()+deque.pop());
            } else if (token.equals("*")) {
                deque.push(deque.pop()*deque.pop());
            } else if (token.equals("/")) {
                //除法需要特殊处理,注意顺序
                Integer pop1 = deque.pop();
                Integer pop2 = deque.pop();
                deque.push(pop2/pop1);
            }else {
                //stringStack.push(token);
                //需要转化为int再进行运算
                deque.push(Integer.valueOf(token));
            }
        }
        return deque.pop();
    }
}

第九天结束,第十天加油!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值