栈相关OJ

目录

1、有效括号

(1)题目描述

(2)解题思路

2、删除字符串中的重复项

(1)题目描述

(2)解题思路

3、比较含退格的字符串

(1)题目描述

(2)解题思路 

4、基本计算器II

(1)题目描述

(2)解题思路 

5、字符串解码

(1)题目描述

(2)解题思路

6、验证栈序列

(1)题目描述

(2)解题思路 

7、最小栈

(1)题目描述

(2)解题思路 

8、逆波兰表达式求值

(1)题目描述

(2)解题思路


1、有效括号

 有效的括号icon-default.png?t=O83Ahttps://leetcode.cn/problems/valid-parentheses/

(1)题目描述

(2)解题思路

1.定义一个字符栈,遍历字符串s

2.如果当前字符是 '(' 或者 '[' 或者 '{',直接入栈  

   如果当前字符是')' 或者 ']' 或者 '}',将栈顶元素取出(取出的栈顶元素必然是左括号),并出栈,将取出的栈顶元素与当前字符做比较(当前字符必然是右括号),判定是否匹配,如果不匹配直接返回false。匹配,继续执行当前逻辑。

   当栈为空时,说明字符串的括号全部都顺利闭合,返回true,否则返回false

class Solution 
{
public:
    bool isValid(string s) 
    {
        
        stack<char> st; // 定义一个字符栈
        for(auto ch : s) // 遍历字符
        {
            if(ch == '(' || ch == '[' || ch == '{') // 左括号入栈
            {
                st.push(ch);
            }
            else // 右括号,取出栈顶元素比较
            {
                
                if(st.empty()) //如果栈为空,则该右括号必然没有与之匹配的左括号,直接返回false
                    return false;

                char top = st.top();
                st.pop();
                if(ch == ')' && top != '(' ||
                   ch == ']' && top != '[' ||
                   ch == '}' && top != '{')
                {
                    return false;
                }
                
            }
        }
        return st.empty();
    }
};

2、删除字符串中的重复项

1047. 删除字符串中的所有相邻重复项icon-default.png?t=O83Ahttps://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string/

(1)题目描述

(2)解题思路

1.定义一个栈,遍历字符串

此处可以使用string模拟栈

2.如果当前栈不为空并且栈顶元素与当前字符串相同,直接将栈顶元素出出去

   否则将当前元素入栈

3.直接将string模拟的栈返回

举个栗子: s = "abbaca"

遍历到第一个字符a的时候,此时栈为空,就将a入栈   

s = "abbaca"

遍历到第二个字符b的时候,栈不为空,当前字符b和栈顶元素a相同吗?不同,入栈 

s = "abbaca"

遍历到第三个字符b的时候,栈不为空,当前字符b和栈顶元素b相同吗?相同,将栈顶元素b出栈

s = "abbaca"

遍历到第四个字符a的时候,栈不为空,当前字符a和栈顶元素a相同吗?相同,将栈顶元素a出栈

s = "abbaca"

遍历到第五个字符c的时候,栈为空,直接入栈

 s = "abbaca"

遍历到第六个字符a的时候,栈不为空,当前字符a和栈顶元素c相同吗?不同,入栈

此时栈的元素就是结果。

这里可以对照着代码看,是非常清晰的。 

class Solution 
{
public:
    string removeDuplicates(string s) 
    {
        string stack;
        for(auto e : s)
        {
            if(!stack.empty() && e == stack.back()) stack.pop_back();
            else stack.push_back(e);
        }
        return stack;
    }
};

3、比较含退格的字符串

844. 比较含退格的字符串icon-default.png?t=O83Ahttps://leetcode.cn/problems/backspace-string-compare/

(1)题目描述

(2)解题思路 

这道题和第二题是极其相似的,可以说是几乎一模一样

1.定义两个栈,这里可以用string模,一般这种与字符串相关的栈题目,都可以用string来充当栈

2.遍历s字符串

   如果栈不为空,并且当前字符是 '#',直接出栈顶元素

   如果当前元素不是 '#',直接入栈

3.遍历t字符串

   如果栈不为空,并且当前字符是 '#',直接出栈顶元素

   如果当前元素不是 '#',直接入栈

4.直接返回两个字符串的比较结果

class Solution 
{
public:
    bool backspaceCompare(string s, string t) 
    {
        string s1, t1;
        for(auto e : s)
        {
            if(s1.size() && e == '#') s1.pop_back();
            else if(e != '#'){
                
                s1.push_back(e);
            }
        }
        for(auto e : t)
        {
            if(t1.size() && e == '#') t1.pop_back();
            else if(e != '#'){
                
                t1.push_back(e);
            }
        }

        return s1 == t1;
    }
};

4、基本计算器II

227. 基本计算器 IIicon-default.png?t=O83Ahttps://leetcode.cn/problems/basic-calculator-ii/

(1)题目描述

(2)解题思路 

这道题是表达式求值,关于这种表达式求值的题,解法都是通用的,就是用两个栈模拟。这道题可以只用一个栈,数值栈,和一个存放运算符的字符变量,来模拟。

这道题只有+-*/四个运算符,因此,优先级最高的当然是 * 和 /。

我们需要用到一个存放整数的栈和一个运算符变量 op

这个栈刚开始是空的,但是这个 op,刚开始是多少呢?刚开始可以为 '+',表示在这个加上这个字符串,比如给的字符串是 s = "3+9-150*3/9",就表示 + 3+9-150*3/9

我们就用s="3+9-150*3/9"这个字符串来模拟一下

s="3+9-150*3/9"

1.遍历字符串s   

s="3+9-150*3/9" 

2.第一个字符是一个整数3,提取出来判断一下op,是+,因此将3入栈

s="3+9-150*3/9"

3.第二个字符是符号+,将op更新为+

s="3+9-150*3/9"

4.第三个字符是一个整数9,提取出来,判定一下op,是+,因此将9入栈

此时你能不能计算3+9的结果呢?是不能的,因为你并不知道下一个运算符是什么,如果是*/,是要先计算9和后面的那一个数的结果的。

s="3+9-150*3/9"

5.第四个字符是符号-,将op更新为-

s="3+9-150*3/9"

6.第5、6、7个字符都是整数,是一个三位数150,要把这个整数提取出来,是很好提取的,写一个循环,定义一个tmp,每次 *= 10,在把当前字符转整数加给tmp,判定一下op,op是负号,将-150入栈

s="3+9-150*3/9"

7.第8个运算符是* ,将更新op为*

s="3+9-150*3/9" 

8.第9个字符是数字3,提取出来,判定一下op,op是*,优先级是最高的,此时可以直接计算,将栈顶的-150取出来并出栈与3做*运算,在将结果-450入栈

s="3+9-150*3/9" 

9. 第10个字符是运算符/,更新op为/

s="3+9-150*3/9" 

10.第11个字符是数字9,提取出来,在看看op为/,优先级最高,可直接运算,将栈顶元素-450取出来并出栈与9做除法运算,将结果-50入栈

11.遍历完毕之后,此时直接将栈的元素做加法运算,就可得出结果-38 

总结:这道题其实就是一个分类讨论的过程,当然,这里题目给的字符串是有空格的,如果有空格跳过即可        

class Solution 
{
public:
    int calculate(string s) 
    {
        char op = '+';
        stack<int> st;
        int i = 0;
        while(i < s.size())
        {
            //空格直接跳过
            if(s[i] == ' ') i++;
            else
            {
                //如果字符是运算符,更新运算符
                if(s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/') op = s[i++];
                //是数字
                else
                {
                    // 1.提取数字
                    int tmp = 0;
                    while(s[i] >= '0' && s[i] <= '9')
                    {
                        tmp *= 10;
                        tmp += s[i] - '0';
                        i++;
                    }
                    // 2.判定运算符
                    if(op == '+') st.push(tmp);
                    else if(op == '-') st.push(-tmp);
                    else if(op == '*')
                    {
                        int top = st.top();
                        st.pop();
                        st.push(top * tmp);
                    }
                    else // '/'
                    {
                        int top = st.top();
                        st.pop();
                        st.push(top / tmp );
                    }
                }
            }
        }
        int ret = 0;
        while(!st.empty())
        {
            ret += st.top();
            st.pop();
        }
        return ret;
    }
};

5、字符串解码

(1)题目描述

394. 字符串解码icon-default.png?t=O83Ahttps://leetcode.cn/problems/decode-string/

(2)解题思路

这道题需要用栈模拟。定义两个栈,一个数字栈,一个字符栈

我们以s = "1[a2[bc]]de3[f]" 字符串为例

1、遍历字符串,碰到第一个字符'1',入数字栈。

2、遍历到'['将'['后面的字符a提取出来,入栈

3、此时遇到到字符'2',入数字栈

4、此时遇到'[' ,将后面的字符'bc'提取出来,入字符栈

5、此时遇到']',数字栈和字符栈出栈, 将2 个 bc,也就是bcbc,可直接bcbc入到字符栈顶吗?不可以呀,因为不知道后面是否还有 ']',因此要将它加入栈顶元素后面,也就是'a'的后面

6、此时又遇到']',将数字栈和字符栈出栈,将1个abcbc,加入栈顶元素后面,可此时将abcbc出栈后,栈为空,访问栈顶不就报错了?因此我们要提前将一个空字符串入栈'',此时将abcbc加入到空字符后面还是abcbc 

7、遇到普通字符,将'de'加入字符栈顶元素后面。

8、遇到数字3,入数字栈 

9、遇到'[',将后面的字符f提取出来入字符栈 

10、遇到']',将数字栈和字符出栈,将fff加入栈顶元素后面,也就是abcdcdefff 

 11、遍历结束后,此时字符栈的栈顶元素就是结果


class Solution 
{
public:
    string decodeString(string s) 
    {
        stack<int> numst; //数字栈
        stack<string> strst; //字符栈
        strst.push(""); //入一个空字符串
        int i = 0, n = s.size();
        while(i < n)
        {
            // 遇到数字,提取出数字,入数字栈
            if(s[i] >= '0' && s[i] <= '9')
            {
                int tmp = 0;
                while(i < n && s[i] >= '0' && s[i] <= '9')
                {
                    tmp *= 10;
                    tmp += s[i++] - '0';
                }
                numst.push(tmp);
            }
            else
            {
                // '['
                if(s[i] == '[')
                {
                    i++;
                    string tmp;
                    while(i < n && s[i] >= 'a' && s[i] <= 'z')
                        tmp += s[i++];
                    strst.push(tmp);
                }
                // ']
                else if(s[i] == ']')
                {
                    string stop = strst.top();
                    strst.pop();
                    int count = numst.top();
                    numst.pop();
                    string newstr;
                    while(count--)
                    {
                        newstr += stop;
                    }
                    string newtop = strst.top();
                    strst.pop();
                    strst.push(newtop + newstr);
                    i++;
                }
                else // 普通字符
                {
                   string tmp;
                    while(i < n && s[i] >= 'a' && s[i] <= 'z')
                        tmp += s[i++];
                    
                    string top = strst.top();
                    strst.pop();
                    strst.push(top + tmp);
                }
            }
        }

        return strst.top();
    }
};

6、验证栈序列

946. 验证栈序列icon-default.png?t=O83Ahttps://leetcode.cn/problems/validate-stack-sequences/

(1)题目描述

(2)解题思路 

这道题,我们在入栈的时候,同时出栈即可。

比如pushed = [1, 2, 3, 4, 5] poped = [4, 5,3,2,1],定义一个poped的下标i = 0, 遍历pushed,将1入栈,然后判定poped[i]也就是4是否等于当前栈顶的元素,如果等于出栈,然后下标i++,进行循环判定

class Solution 
{
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) 
    {
        vector<int> st;
        int i = 0;
        for(auto e : pushed)
        {
            // 入栈的同时出栈
            st.push_back(e);
            while(!st.empty() && popped[i] == st.back())
            {
                st.pop_back();
                i++;
            }
        }
        return st.empty();
    }
};

7、最小栈

155. 最小栈icon-default.png?t=O83Ahttps://leetcode.cn/problems/min-stack/

(1)题目描述

(2)解题思路 

这道题最主要的是我们如何获取栈中的最小元素呢?遍历吗?每次遍历一下,取出最小的元素,可以是可以但是效率太低了,每一次取都要去遍历,有没有更好的方法呢?我们可以用两个栈,一个栈存放数据,一个栈存放栈中的最小元素。比如说7,5,2,2,5

7的时候入栈,此时最小栈为空,也要入7,然后到5,5入栈,5比最小栈的栈顶7小,入栈。2入数据栈,2比最小栈栈顶元素小,入栈,下一个2,这个2要不要入最小栈呢?是要的,否则出栈时会问题的。

此时我们取栈顶最小元素,是5,但栈的最小元素应该是2呀。因此,如果这个元素和最小栈的栈顶元素<=的时候,都要入栈

 

class MinStack {
public:
    MinStack() {
        // 不需要初始化
    }
    
    void push(int val) {
        st.push(val);
        if(min_st.empty() || val <= min_st.top())
        {
            min_st.push(val);
        }

    }
    
    void pop() 
    {
        if(st.top() == min_st.top())
        {
            min_st.pop();
        }
        st.pop();

    } 
    
    int top() {
        return st.top();
    }
    
    int getMin() {
        return min_st.top();
    }
    stack<int> st;
    stack<int> min_st;
};

8、逆波兰表达式求值

150. 逆波兰表达式求值icon-default.png?t=O83Ahttps://leetcode.cn/problems/evaluate-reverse-polish-notation/

(1)题目描述

(2)解题思路

我们平常写的表达式都是中缀表达式,比如说2 * 4 + 1,中缀表达式计算是很不友好的,因为涉及到优先级,我们人可以直接自己判断优先级,但是计算机就没那么容易了,因此就有了后缀表达式,比如说示例1: 2,1,+,3,*,后缀表达式如何计算呢,遇到符号直接运算,2 + 1 = 3,然后再遇到乘号,用2 + 1的结果3,在乘以3。

用栈是很好模拟的,比如说示例2的 2,1,+,3,*

遇到操作数直接入栈, 2,1入栈

遇到+,取出栈顶两元素,计算结果入栈

遇到3,入栈

遇到*,取出栈顶2元素,计算结果入栈,注意,这里先出来的是右操作数,在计算除法的时候不要左右操作数写反了。

最后栈顶元素即为表达式结果 

class Solution {
public:
    int evalRPN(vector<string>& tokens) 
    {
        stack<int> st;
        for(auto& e : tokens)
        {
            if(e == "+" || e == "-" || e == "*" || e == "/")
            {
                int right = st.top(); st.pop();
                int left = st.top(); st.pop();

                if(e == "+")
                    st.push(left + right);
                else if(e == "-")
                    st.push(left - right);
                else if(e == "*")
                    st.push(left * right);
                else
                    st.push(left / right);
            }
            else
            {
                st.push(stoi(e));
            }
        }
        return st.top();
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值