Day8| 20. 有效的括号、1047. 删除字符串中的所有相邻重复项 、150. 逆波兰表达式求值

20. 有效的括号

题目链接/文章讲解/视频讲解:代码随想录

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

有效字符串需满足:

  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。
  • 注意空字符串可被认为是有效字符串。

 思路:

        对栈有了一些理解后,看了Carl的思路讲解,然后独立AC了本道题。主要思路就是注意三点。一、字符串左括号是否多余?二、字符串括号顺序是否正确?三、字符串右括号是否多余?当我们遇见左括号时,我们先按顺序将左括号对应的右括号存入栈中,如果遇见对应的右括号,就从栈里面删除,直到最后栈为空则字符串有效。

情况一:

 

情况二:

情况三:

代码

class Solution {
public:
    bool isValid(string s) {
        stack<int> stackin;
        for(int i = 0; i < s.size(); i++){
            if(s[i] == '(') {
                stackin.push(')');
                continue;
            }
            else if(s[i] == '{'){
                 stackin.push('}');
                 continue;
            }
            else if(s[i] == '['){ 
                stackin.push(']');
                continue;
            }
            else if(!stackin.empty() && s[i] == stackin.top()){
                stackin.pop();
                continue;
            }
            else{
                return false;
            }
        }

        return stackin.empty() ? true : false;
    }
};

理解这种思路, 左右对应,左添右删。 

 

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

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

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

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

示例:

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

思路:

        这道题就像是开心消消乐,当我消除了两个一样的字符之后,我们需要考虑这两个字符串两侧的字符串是否也需要消除?从代码随想录理解到:栈是用来存取我们已经遍历过的元素,有效的括号那道题也是这样,当我们遍历到右括号时,我们需要去检查之前是否遇见过左括号。 简单AC。

代码实现 :

class Solution {
public:
    string removeDuplicates(string s) {
        stack<char> stackin;
        stack<char> stackout;
        for(int i = 0; i < s.size(); i++){
            if(stackin.empty() || s[i] != stackin.top()){
                stackin.push(s[i]);
            }
            else{
                stackin.pop();
            }
        }

        while(!stackin.empty()){
            stackout.push(stackin.top());
            stackin.pop();
        }

        string res;
        while(!stackout.empty()){
            res.push_back(stackout.top());
            stackout.pop();
        }
        
        return res;
    }
};

想着联动一下前面学习的用栈实现队列, 其实这里如果使用队列会更简单一点,也可以只使用一个栈,然后使用reverse()函数来反转一下输出即可。

 150. 逆波兰表达式求值

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

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

注意:

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

 思路:

        理解逆波兰表达式的求值思路,即取当前两个数存入栈,遇见符号就拿出进行计算,然后将计算结果压入栈。最后栈中所得值即为结果。

        主要是一些特殊的小细节需要去认真学习,比如:从字符串容器中读出的数字如何压入到整型的栈中?得到的结果需不需要担心溢出问题?

代码:

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

        return (long long) stackin.top();
    }
};

这里可以考虑将数字插入栈放在if处,运算过程放在else处,可以省去一些代码:

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<long long> stackin;
        long long temp1, temp2;
        for(int i = 0; i < tokens.size(); i++){
            if(tokens[i] != "+" && tokens[i] != "-" && tokens[i] != "*" && tokens[i] != "/"){
                stackin.push(atoi(tokens[i].c_str()));
            }
            else{
                temp1 = (long long) stackin.top();
                stackin.pop();
                temp2 = (long long) stackin.top();
                stackin.pop();
                if(tokens[i] == "+"){
                    stackin.push(temp2 + temp1);
                }
                else if(tokens[i] == "-"){
                    stackin.push(temp2 - temp1);
                }
                else if (tokens[i] == "*"){
                    stackin.push(temp2 * temp1);
                }
                else if (tokens[i] == "/"){
                    stackin.push(temp2 / temp1);
                }
            }
        }

        return (long long) stackin.top();
    }
};

 总结:

        今天的三道题算是比较简单的,理解了栈的后进先出思想后,熟练使用pop(),top(),push()函数,就能够比较好的解决一些栈相关的问题。尤其是需要检查先前遍历的元素问题可以用栈来进行解决。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值