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

目录:

解题及思路学习

20. 有效的括号

https://leetcode.cn/problems/valid-parentheses/

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

有效字符串需满足:

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

示例 1:

输入:s = "()"
输出:true

思考:用一个栈来存储,左括号就入栈,右括号就出栈。出栈如果不是对应的符号,则false。如果最后栈为空,则返回true。

class Solution {
public:
    bool isValid(string s) {
        if (s.size() % 2 != 0) return false;
        stack<int> st;
        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();
            }
        }
        return st.empty();
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)

第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false

第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false

第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false

那么什么时候说明左括号和右括号全都匹配了呢,就是字符串遍历完之后,栈是空的,就说明全都匹配了。

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

https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string/

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

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

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

示例:

输入:"abbaca"
输出:"ca"

思考:删除相邻的重复项。双指针不太好操作,可以利用栈的特性,进行删除。

1、利用栈进行重复元素去除。2、遍历得到栈中的元素,此时是反序的。3、再逆序一下。

class Solution {
public:
    string removeDuplicates(string s) {
        stack<char> st;
        for (char si : s) {
            if (!st.empty() && si == st.top()) {
                st.pop();
            } else {
                st.push(si);
            }
        }
        string result = "";
        while(!st.empty()) {
            result += st.top();
            st.pop();
        }
        reverse(result.begin(), result.end());
        return result;
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)

直接使用string 当做栈也行

class Solution {
public:
    string removeDuplicates(string s) {
        string result;
        for (char si : s) {
            if (!result.empty() && si == result.back()) {
                result.pop_back();
            }else {
                result.push_back(si);
            }
        }
        return result;
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(1),返回值不计空间复杂度

递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。

相信大家应该遇到过一种错误就是栈溢出,系统输出的异常是Segmentation fault(当然不是所有的Segmentation fault 都是栈溢出导致的) ,如果你使用了递归,就要想一想是不是无限递归了,那么系统调用栈就会溢出。

而且在企业项目开发中,尽量不要使用递归!在项目比较大的时候,由于参数多,全局变量等等,使用递归很容易判断不充分return的条件,非常容易无限递归(或者递归层级过深),造成栈溢出错误(这种问题还不好排查!)

150. 逆波兰表达式求值

https://leetcode.cn/problems/evaluate-reverse-polish-notation/

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

示例 1:

输入:tokens = ["2","1","+","3","*"]
输出:9

思考:逆波兰表达式,遇到数值就放到栈里面,遇到符号就取出栈顶的两个数据,进行运算之后,讲结果再压入栈中。最后返回总的结果值。

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 nums1 = st.top();
                st.pop();
                long long nums2 = st.top();
                st.pop();
                if (tokens[i] == "+") st.push(nums2 + nums1);
                if (tokens[i] == "-") st.push(nums2 - nums1);
                if (tokens[i] == "*") st.push(nums2 * nums1);
                if (tokens[i] == "/") st.push(nums2 / nums1);
            }else {
                st.push(stoll(tokens[i]));
            }
        }
        int result = st.top();
        st.pop();
        return result;
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)

思路不难,但是代码细节比较容易出错。

1、应该用双引号:“”

2、容易打错字符,搞错括号

复盘总结

个人反思

主要把栈的相关题刷了一下。

栈对于成对的符号检测,逆波兰表达式运算应用广泛。

栈一个特征点就是能知道遍历的上一个元素的值,用于后序比较。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我来回答你的问题。 1. 给出一个字符串,找出字符串所有的单词。 可以通过正则表达式来实现,代码如下: ```javascript const str = "hello world, I'm a developer"; const words = str.match(/\b\w+\b/g); console.log(words); // ["hello", "world", "I'm", "a", "developer"] ``` 这里使用了 `\b\w+\b` 匹配单词的正则表达式,其 `\b` 表示单词边界,`\w+` 表示匹配一个或多个字母数字下划线字符。 2. 从键盘输入两个字符串,在第一个字符串删除第二个字符串的字符。 可以先将第二个字符串转换为字符数组,然后遍历该数组,在第一个字符串删除对应的字符。代码如下: ```javascript const str1 = "hello world"; const str2 = "o"; const chars = str2.split(""); for (let i = 0; i < chars.length; i++) { const char = chars[i]; str1 = str1.replace(new RegExp(char, "g"), ""); } console.log(str1); // "hell wrld" ``` 这里使用了 `split` 将第二个字符串转换为字符数组,然后遍历该数组,使用 `replace` 在第一个字符串删除对应的字符。 3. 使用正则表达式匹配日期格式,如 2022年11月30日。 可以使用如下正则表达式匹配日期格式: ```javascript const str = "2022年11月30日"; const dateRegex = /(\d{4})年(\d{1,2})月(\d{1,2})日/; const match = str.match(dateRegex); const year = match[1]; const month = match[2]; const day = match[3]; console.log(`${year}-${month}-${day}`); // "2022-11-30" ``` 这里使用了 `(\d{4})年(\d{1,2})月(\d{1,2})日` 匹配日期格式的正则表达式,其 `(\d{4})` 表示匹配 4 个数字的年份,`(\d{1,2})` 表示匹配 1 到 2 个数字的月份和日期。然后使用 `match` 方法匹配字符串,获取到匹配的年份、月份和日期,并使用模板字符串拼接成标准日期格式输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值