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

20. 有效的括号 

文档讲解:代码随想录 (programmercarl.com)

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

状态:没做出来

        其实这个题目的描述是很模糊的,这就需要去仔细地想各种不匹配的情况,并且总结出规律,对刚刚接触这个题目的人来说并不是那么友好。

        看了视频之后,总结出其实不匹配的情况就三种,用语言总结其实就两种:1. 左右括号数量不匹配 2.相邻括号类型不匹配。

        但是,左右括号数量不匹配其实是两种情况 ,因为在用栈来解决这类符号匹配问题的时候,如果左边括号(例如“{”)数量比右边(例如“}”)的多,那就会出现明明已经遍历完了整个字符串,但是栈内还是有元素,如果右边括号数量比左边的多,就会出现正准备匹配的时候,发现栈空了,没有元素给右边的括号匹配。

        而相邻括号类型不匹配,就是在匹配的时候发现栈顶的元素类型(这里指的是“}”“)”“]”三种类型),和自身的类型对应不上。

class Solution {
public:
    bool isValid(string s) {
        stack sta;
        for(int i = 0; i < s.size(); i++){
            if(s.size() % 2 != 0)return false;
            else if(s[i] == '(')sta.push(')');
            else if(s[i] == '{')sta.push('}');
            else if(s[i] == '[')sta.push(']');
            else if(sta.empty() || s[i] != sta.top()){
                return false;
            }
            else{
                sta.pop();
            }
        }
        if(!sta.empty())return false;
        return true;
    }
};

        这里说一下为什么push的是相反方向的括号,这是为了让匹配的时候可以直接匹配不用考虑条件,即不用考虑左括号怎么映射到对应的右括号。

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

文档讲解:代码随想录 (programmercarl.com)

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

状态:AC

        因为只用匹配相邻的字符,所以想到用栈更加方便。

        每一位push到栈里之前,要判断一下当前位置元素是否和栈顶元素相等,因为栈是后进先出的,所以栈顶元素就是字符串当前元素的上一个元素,这就是在判断相邻元素是否相等。

        当然,判断相等之前要判断是否栈空,不然就涉及访问空栈的异常。

        遍历完之后,栈内的元素就是处理好了之后字符串的所有元素,因为我已经记录下了所有的元素,所以可以直接给字符串缩容,并且从字符串末尾开始赋值,因为栈是后进先出的。看题解的时候发现代码中新建了一个字符串来存栈内元素,感觉有点浪费空间了。

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

150. 逆波兰表达式求值

文档讲解:代码随想录 (programmercarl.com)

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

状态:没做出来

        看完题目,其实已经交代得很清楚了,什么是逆波兰表达式?简单理解一下就是平时加减乘除的数学表达式,都是树的中序遍历,现在变成了树的后序遍历而已。

        而且题目还提到

  • 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中

        思路已经明确了,然后就是写代码,写代码过程中我认为比较棘手的三个点:1. 怎么判断遍历的当前元素是数字还是字符?其实这个很简单,字符就加减乘除四种情况,在if语句中判断一下,剩下的就都是数字了。当时我是先判断的数字,所以没那么顺。2. 怎么把字符串转变为整型?C++标准库提供了相应的函数stoi()(将字符串转成int类型),stoll(将字符串转成long long类型)。3. 每次运算之后的结果存到哪里?其实可以继续存到栈里,仔细想想这个操作并不影响后面的入栈出栈,并且还让代码标准化了,省去了多余的代码。

        一开始用int发现总是越界,最后看题解说是改了用例,所以要把所有int类型全部改成long long 类型。另外要注意push的时候为什么是tmp2在前面,因为栈是后进先出的,所以tmp1存的才是运算符后面的操作数,加法乘法没关系,主要是减法和除法,减数和除数不一样会影响结果。

class Solution {
public:
    int evalRPN(vector& tokens) {
        stack st;
        for(int i = 0; i 

        三道题目写下来,发现栈的逻辑并不难,难的是识别什么时候要运用到栈。

你可能感兴趣的:(算法)