代码随想录【day 11 栈与队列】| 20. 有效的括号 1047. 删除字符串中的所有相邻重复项 150. 逆波兰表达式求值


LeetCode 20. 有效的括号

题目链接:20.有效的括号
卡哥文解
视频讲解
  • 题目描述: 给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
    有效字符串需满足:
  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。
  • 每个右括号都有一个对应的相同类型的左括号。
解题思路 (栈的经典应用)

1、遍历字符串 遇到左方向的括号将对应的右方向括号压入栈 在遍历时 将字符串遇到的右方向括号和压入的右方向括号进行匹配 若相同则消去 遇到以下三种情况 则return false
2、不匹配的情况:左括号多了 / 右括号多了 / 括号不匹配

  • 左括号多:字符串遍历完 栈不为空
  • 括号类型不匹配:栈顶元素 top 和右方向的括号类型不匹配; (例如:[ { ( } ] 压入栈为 ) } ])
  • 右括号多:字符串没遍历完 栈为空

3、剪枝:如果字符串的长度为奇数,一定不有效

实现难点

1、空栈取栈顶元素会报异常
2、当右方向括号和压入的右方向括号进行匹配时,将栈顶元素弹出

代码实现
class Solution {
public:
    stack <char> st;
    bool isValid(string s) {
        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;
            else st.pop();
        }
        // 若字符串遍历完 栈不为空 返回false
        return st.empty();
    }
};

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

题目链接:LeetCode1047.删除字符串中的所有相邻重复项
卡哥文解
视频讲解
  • 题目描述: 给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
  • 在 S 上反复执行重复项删除操作,直到无法继续删除。
  • 在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
解题思路
  • 利用栈存放遍历过的元素,当遍历当前元素时,去栈中查看是否遍历过相同数值的相邻元素
实现难点
  • 不仅删除相邻项 若删除之后又有相连处 还要继续删除
  • 若用栈实现 返回最终结果时 栈内元素和结果字符串相反 还需要反转一下 故还可以直接使用字符串模拟栈
  • 取字符串尾部 : result.back() 将元素放到字符串的尾部: result.push_back();
代码实现1(直接利用栈)
class Solution {
public:
    string removeDuplicates(string s) {
        stack<char>st;
        // 加元素的情况 当栈为空 或者 栈顶元素与字符串遍历元素不相等时
        for(int i=0;i<s.size();i++){
            if(st.empty() || st.top()!=s[i]) st.push(s[i]);
            else st.pop();
        }
        string result;
        // 先取top 再弹出
        while(!st.empty()){
            result += st.top();
            st.pop();
        }
        reverse(result.begin(), result.end());
        return result;

    }
};
代码实现2(字符串模拟栈)
class Solution {
public:
    string removeDuplicates(string S) {
        string result;
        for(char s : S) {
            if(result.empty() || result.back() != s) {
                result.push_back(s);
            }
            else {
                result.pop_back();
            }
        }
        return result;
    }
};

LeetCode 150. 逆波兰表达式求值

题目链接:150.逆波兰表达式求值
卡哥文解
视频讲解
  • 题目描述: 给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。
  • 请你计算该表达式。返回一个表示表达式值的整数。
  • 注意:
  • 有效的算符为 ‘+’、‘-’、‘*’ 和 ‘/’ 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。
解题思路

1、逆波兰表达式是后缀表达式,直接根据顺序处理而不需要考虑括号优先级
2、遇到数字则入栈,遇到运算符则取出栈顶两个数字进行计算,并将计算结果压入栈中。

(补:当vector当作形参输入到函数时,可以加& 或者不加)
带&表示传入函数的是vector的引用(即物理位置),函数内部对vector改动,vector就会改变;
不带&表示传入的是vector的复制品(开辟了另一块位置),函数内部对其改动,不会影响原本的vector;
vector< int> nums:nums是一个容器变量,容器名称为vector,容器内存的数据为int型
vector< int> &nums:nums为一个引用,引用的内容是vector这个容器内部存放的整型数据

实现难点

1、怎么样 实现将操作数进行运算:对四个运算符再分别进行讨论
2、因为向栈里添加元素的情况较复杂 所以可以先讨论 遇到操作符进行的运算 else下添加元素
3、在进行减法以及除法操作时,弄清操作数的位置
4、读入的是字符串 在添加数字入栈时 需调用stoll:将字符串转换为long long

代码实现
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int>st;
        for(int i=0;i<tokens.size();i++){
            // 向栈里添加元素 栈为空以及没有遇到操作符
            if(tokens[i]=="+" ||tokens[i]=="-" || tokens[i]=="*" || tokens[i]=="/"){
                int opre1 = st.top();
                st.pop();
                int opre2 = st.top();
                st.pop();
                // 怎么样 实现将操作数进行运算 对四个运算符分别讨论
                if(tokens[i] == "+") st.push(opre1+opre2);
                if(tokens[i] == "-") st.push(opre2-opre1);
                if(tokens[i] == "*") st.push(opre1*opre2);
                if(tokens[i] == "/") st.push(opre2/opre1); //弄清楚谁是除数
            }
            else{
                st.push(stoll(tokens[i]));
            }

        }
        return st.top();
    }
};

补充

push与 push_back都是向数据结构中添加元素
push_back() 在Vector最后添加一个元素(参数为要插入的值)
pop_back()删除vector容器中的最后一个元素

vector<int> vi;
C++ vector 排序 sort(vi.begin(),vi.end()); // 从小到大
反转 reverse(vi.begin(),vi.end());// 从大到小
查找 find(vi.begin(),vi.end(),3);
定义stack 对象的示例代码如下:
stack<int> s1;
stack<string> s2;
stack 的基本操作有:
入栈,如例:s.push();在栈顶增加元素
出栈,如例:s.pop();注意,出栈操作只是删除栈顶元素,并不返回该元素。
访问栈顶,如例:s.top()
判断栈空,如例:s.empty(),当栈空时,返回true。
访问栈中的元素个数,如例:s.size()。
queue 的基本操作有:
入队,如例:q.push(x); 将x 接到队列的末端。
出队,如例:q.pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
访问队首元素,如例:q.front(),即最早被压入队列的元素。
访问队尾元素,如例:q.back(),即最后被压入队列的元素。
判断队列空,如例:q.empty(),当队列空时,返回true。
访问队列中的元素个数,如例:q.size()

day11总结复盘

1、栈结构的特殊性 非常适合做对称匹配 或者 相邻字母的特殊判断(左括号 右括号匹配 或者 相同 或者符合 遇到操作符进行操作再压入)
2、企业项目开发尽量不要使用 递归! 项目较大时,由于参数多,全局变量等,使用递归很容易判断不充分return条件,容易无限递归(或递归层级过深),造成栈溢出错误。
3、学会C++的一种循环简便写法 for(Char s:S) 则s是逐个取出的字符

参考链接
https://blog.csdn.net/u013630349/article/details/46853297
https://blog.csdn.net/qq_52876054/article/details/119270241?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7ERate-2-119270241-blog-121026264.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7ERate-2-119270241-blog-121026264.pc_relevant_aa&utm_relevant_index=3
https://blog.csdn.net/leviopku/article/details/121026264

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值