刷题第九天 栈与队列● 20. 有效的括号● 1047. 删除字符串中的所有相邻重复项● 150. 逆波兰表达式求值

20. 有效的括号

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

有效字符串需满足:

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

示例 1:

  • 输入: "()"
  • 输出: true

示例 2:

  • 输入: "()[]{}"
  • 输出: true

示例 3:

  • 输入: "(]"
  • 输出: false

示例 4:

  • 输入: "([)]"
  • 输出: false

示例 5:

  • 输入: "{[]}"
  • 输出: true

解题思想

括号匹配是使用栈解决的经典问题。由于栈结构的特殊性,非常适合做对称匹配类的题目。

首先要弄清楚,字符串里的括号不匹配有几种情况。一上来就写代码,可能会越写越乱。建议在写代码之前要分析好有哪几种不匹配的情况,如果不在动手之前分析好,写出的代码也会有很多问题。

先来分析一下 这里有三种不匹配的情况,

  1. 第一种情况,字符串里左方向的括号多余了 ,所以不匹配。 

    括号匹配1

  2. 第二种情况,括号没有多余,但是 括号的类型没有匹配上。 

    括号匹配2

  3. 第三种情况,字符串里右方向的括号多余了,所以不匹配。 

    括号匹配3

我们的代码只要覆盖着三种情况就能找出所有不匹配的情况了。

 如上面动画所示,当遍历到左括号,就把相应的右括号存入栈,这是顺序存入的,对应的右括号是晚进先出,与右括号正确的顺序相符。当遍历到右括号,就弹出栈第一个元素与之相比,如果相同就继续,不同就返回false(第二种情况);如果还没有遍历完,栈就已经空了,那就是第三种情况,也返回false;如果遍历完,栈还没空,就是第一种情况,也是返回false。

class Solution {
public:
    bool isValid(string s) {
        stack<char> st;
        if(s.size()%2 != 0) return false;
        for(int i=0;i<s.size();i++){
            if(s[i] == '(') st.push(')');
            else if(s[i] == '[') st.push(']');
            else if(s[i] == '{') st.push('}');
            else if(st.empty() || st.top() != s[i]) return false;   
            //先判断是否空,避免空的时候取top非法。
            else st.pop();
        }
        return st.empty();
    }
};

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

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

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

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

示例:

输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。

解题思路

这道题是让我们删除相邻元素,删除相邻元素的判断是什么,就是判断当前值是不是和前一个值相等,就需要存储前一个遍历的值,那么如何记录前面遍历过的元素呢?

栈就非常符合这种情况,并且可以直接消除“abba”这种情况,因为把遍历过的元素存入栈,然后把当前元素和栈顶元素比较,如果相等就弹出,如果不等就存入,最后返回栈中元素即可。

 

class Solution {
public:
    string removeDuplicates(string S) {
        stack<char> st;
        for (char s : S) {
            if (st.empty() || s != st.top()) {
                st.push(s);
            } else {
                st.pop(); // s 与 st.top()相等的情况
            }
        }
        string result = "";
        while (!st.empty()) { // 将栈中元素放到result字符串汇总
            result += st.top();
            st.pop();
        }
        reverse (result.begin(), result.end()); // 此时字符串需要反转一下
        return result;

    }
};

可以直接用字符串作为栈,这样不用最后反转字符串的那一步,封闭字符串的头部即可。

class Solution {
public:
    string removeDuplicates(string s) {
        string result;
        for(char a:s){
            if(result.empty() || result.back() != a) result.push_back(a);
            else result.pop_back();
        }
        return result;
    }
};

150. 逆波兰表达式求值

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

有效的算符为 '+'、'-'、'*' 和 '/' 。
每个操作数(运算对象)都可以是一个整数或者另一个表达式。
两个整数之间的除法总是 向零截断 。
表达式中不含除零运算。
输入是一个根据逆波兰表示法表示的算术表达式。
答案及所有中间计算结果可以用 32 位 整数表示。

 就是相当于把需要进行运算的两个数字存在前面,然后运算符在后,看动画比较清晰。本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么这岂不就是一个相邻字符串消除的过程,和1047.删除字符串中的所有相邻重复项 (opens new window)中的对对碰游戏是不是就非常像了。

 这整个过程就是遇到数字就把数字存进栈,遇到运算符就把栈前二的数字取出来进行运算,运算结果存入栈,以此循环。遍历完成返回栈中仅剩的一个值即可。

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<long long>st;
        for(int i=0;i<tokens.size();i++){
            if(tokens[i] == "+" || tokens[i]=="-" || tokens[i]=="*" || tokens[i]=="/"){
                long long num1 = st.top();
                st.pop();
                long long num2 = st.top();
                st.pop();
                if(tokens[i] == "+") st.push(num2+num1);
                if(tokens[i] == "-") st.push(num2-num1);
                if(tokens[i] == "*") st.push(num2*num1);
                if(tokens[i] == "/") st.push(num2/num1);
            }
            else st.push(stoll(tokens[i]));
        }
        return st.top();

    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值