代码随想录算法训练营第十一天

栈和队列[LeetCode20有效的括号、LeetCode1047删除字符串中所有的相邻重复项、LeetCode150逆波兰表达式求值]

Posted by ThreeStones1029 on April 13, 2024

[TOC]

第一题

LeetCode20有效的括号

解法一[存储左括号]

  • 空间复杂度O(n)

  • 空间复杂度O(n)

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

解法二[存储右括号]

  • 空间复杂度O(n)
  • 空间复杂度O(n)
class Solution {
public:
    bool isValid(string s) {
        stack<char> right_symbol;
        if (s.size() % 2 != 0) return false;
        for (int i = 0; i < s.size(); i++){
            if (s[i] == '('){
                right_symbol.push(')');
            }
            else if (s[i] == '['){
                right_symbol.push(']');
            }
            else if (s[i] == '{'){
                right_symbol.push('}');
            }
            else if (!right_symbol.empty() && s[i] == right_symbol.top()){
                right_symbol.pop();
            }
            else{
                return false;
            }
        }
        return right_symbol.empty();
    }
};

总结

  • 由于以前做过这样的题所以大概还是不难写出来,自己首先写的是左括号存储的方法,这种方法对于条件处理相比右括号存储的方法更多一点.
  • 注意只要使用栈的pop以及top都需要先判断empty.
  • 右括号存储的方式目前看起来更为方便.

第二题

LeetCode1047删除字符串中所有相邻重复项

解法一[栈的方式]

  • 时间复杂度O(n)
  • 空间复杂度O(n)
class Solution {
public:
    string removeDuplicates(string s) {
        stack<char> char_stack;
        stack<char> result;
        string result_string(s);
        char_stack.push(s[0]);
        // 删除重复元素,判断栈顶元素与当前元素是否相等
        for (int i = 1; i < s.size();i++){
            if (!char_stack.empty() && char_stack.top() == s[i]){
                // 相等则出栈
                char_stack.pop();
            }
            else{
                // 不相等则入栈
                char_stack.push(s[i]);
            }
        }
        // 翻转栈
        while (!char_stack.empty()){
            result.push(char_stack.top());
            char_stack.pop();
        }
        // 将栈的元素以字符串的形式输出
        int n = result.size();
        int i = 0;
        while (i < n){
            result_string[i] = result.top();
            result.pop();
            i++;
        }
        result_string.resize(n);
        return result_string;
    }
};

解法二[原地暴力删除]

  • 时间复杂度O(n * n)
  • 空间复杂度O(1)
class Solution {
public:
    string removeDuplicates(string s) {
        int n = s.size();
        int i = 1;
        while (i < n){
            if (i - 1 >= 0 && s[i] == s[i - 1]){
                // 当有相等的字符,则向前移动两个字符
                for (int j = i; j < n - 1; j++){
                    s[j - 1] = s[j + 1];
                }
                n -= 2;
                i -= 2;
            }
            else{
                i += 1;
            }
        }
        s.resize(n);
        return s;
    }
};

解法三[字符串作为栈]

  • 时间复杂度O(n)
  • 空间复杂度O(n)
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;
    }
};

总结

  • 整体看来这题算是比较简单,也较短时间能够写出来,使用栈的方式应该更为简单.

  • 对于暴力法原地删除两个元素,主要时间消耗在移动元素上.

  • 开始找回题感了.

第三题

LeetCode150逆波兰表达式求值

解法一[栈保存数字]

  • 时间复杂度O(n)
  • 空间复杂度O(n)
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> number;
        for (int i = 0; i < tokens.size(); i++){
            // 输入数字,需要将字符串转为数字
            if (tokens[i] != "+" && tokens[i] != "-" && tokens[i] != "*" && tokens[i] != "/"){
                int int_number = std::stoi(tokens[i]);
                number.push(int_number);
            }
            else{
                // 主要在于知道顺序,减法以及除法需要有顺序,在逆波兰表达式第一个栈顶的为表达式的第二项
                int second = number.top();
                number.pop();
                int first = number.top();
                number.pop();
                if (tokens[i] == "+"){
                    number.push(first + second);
                }
                if (tokens[i] == "-"){
                    number.push(first - second);
                }
                if (tokens[i] == "*"){
                    number.push(first * second);
                }
                if (tokens[i] == "/"){
                    number.push(first / second);
                }
            }
        }
        return number.top();
    }
};

总结

  • 总体看来这题主要考察是否了解逆波兰表达式
  • 学习std::stoi()将字符串转为数字
  • 对于表达式求值顺序需要考虑清楚

总结

  • 因为各种各样的原因,停了一个礼拜多,果然和卡哥说的一样,停了超过三天以上感觉丧失了题感.目前正在赶进度中.
  • 这一天的总体难度不高,只要利用好栈的性质会比较好解决.