【优选算法之栈】No.13--- 经典栈算法


前言

在这里插入图片描述

👧个人主页:@小沈YO.
😚小编介绍:欢迎来到我的乱七八糟小星球🌝
📋专栏:优选算法
🔑本章内容:栈
记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~


一、栈示例:

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

  1. 题⽬链接:1047. 删除字符串中的所有相邻重复项
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(栈):
    算法思路:
    本题极像我们玩过的「开⼼消消乐」游戏,仔细观察消除过程,可以发现本题与我们之前做过的「括号匹配」问题是类似的。当前元素是否被消除,需要知道上⼀个元素的信息,因此可以⽤「栈」来保存信息。
    但是,如果使⽤ stack 来保存的话,最后还需要把结果从栈中取出来。不如直接⽤「数组模拟⼀个栈」结构:在数组的尾部「尾插尾删」,实现栈的「进栈」和「出栈」。那么最后数组存留的内容,就是最后的结果。
  4. C++代码
class Solution {
public:
    string removeDuplicates(string s) 
    {
        stack<char> st;
        for(int i=0;i<s.size();i++)
        {
            if(st.empty())st.push(s[i]);
            else
            {
                if(st.top()==s[i])
                {
                    st.pop();
                    continue;
                }
                else
                st.push(s[i]);
            }
        }
        string str;
        while(!st.empty())
        {
            str+=st.top();
            st.pop();
        }
        reverse(str.begin(),str.end());
        return str;
------------------------------------------------------------------------------------------------
        //模拟栈
        string ret;
        for(auto&e:s)
        {
            if(ret.size()&&e==ret.back())ret.pop_back();
            else ret+=e;
        }
        return ret;
    }
};

1.2 ⽐较含退格的字符串

  1. 题⽬链接:844. ⽐较含退格的字符串
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(⽤数组模拟栈):
    算法思路:
    由于退格的时候需要知道「前⾯元素」的信息,⽽且退格也符合「后进先出」的特性。因此我们可以使⽤「栈」结构来模拟退格的过程。
    • 当遇到⾮ # 字符的时候,直接进栈;
    • 当遇到 # 的时候,栈顶元素出栈。
    为了⽅便统计结果,我们使⽤「数组」来模拟实现栈结构
  4. C++代码
class Solution {
public:
    bool backspaceCompare(string s, string t) 
    {
        stack<char>st1,st2;
        for(auto&e:s)
        {
            if(e!='#')st1.push(e);
            else
            {
                if(!st1.empty())st1.pop();
            }
        }
        for(auto&e:t)
        {
            if(e!='#')st2.push(e);
            else
            {
                if(!st2.empty())st2.pop();
            }
        }
        if(st1.size()!=st2.size())return false;
        while(!st1.empty())
        {
            if(st1.top()==st2.top())
            {
                st1.pop();st2.pop();
            }
            else return false;
        }
        return true;
    }
};
---------------------------------------------------------------------------------------------

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

1.3 基本计算器 II

  1. 题⽬链接:227. 基本计算器 II
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(栈):
    算法思路:
    由于表达式⾥⾯没有括号,因此我们只⽤处理「加减乘除」混合运算即可。根据四则运算的顺序,我们可以先计算乘除法,然后再计算加减法。由此,我们可以得出下⾯的结论:
    • 当⼀个数前⾯是 ‘+’ 号的时候,这⼀个数是否会被⽴即计算是「不确定」的,因此我们可以先压⼊栈中;
    • 当⼀个数前⾯是 ‘-’ 号的时候,这⼀个数是否被⽴即计算也是「不确定」的,但是这个数已经和前⾯ 的 - 号绑定了,因此我们可以将这个数的相反数压⼊栈中;
    • 当⼀个数前⾯是 ‘*’ 号的时候,这⼀个数可以⽴即与前⾯的⼀个数相乘,此时我们让将栈顶的元素乘上这个数;
    • 当⼀个数前⾯是 ‘/’ 号的时候,这⼀个数也是可以⽴即被计算的,因此我们让栈顶元素除以这个数。
    当遍历完全部的表达式的时候,栈中剩余的「元素之和」就是最终结果。
  4. C++代码
class Solution {
public:
    int calculate(string s) 
    {
        stack<int> st;
        char op='+';
        for(int i=0;i<s.size();)
        {
            int tmp=0;
            if(s[i]==' ')i++;
            else if(s[i]>='0'&&s[i]<='9')
            {
                while(i<s.size()&&(s[i]>='0'&&s[i]<='9'))
                    tmp=tmp*10+(s[i++]-'0');
                if(op=='+') st.push(tmp);
                else if(op=='-') st.push(-tmp);
                else if(op=='*')st.top()*=tmp;
                else st.top()/=tmp;
            }
            else op=s[i++];
        }
        int sum=0;
        while(!st.empty())
        {
            sum+=st.top();
            st.pop();
        }
        return sum;
    }
};
----------------------------------------------------------------------------------------
//数组模拟栈
class Solution {
public:
    int calculate(string s) 
    {
        vector<int> v;
        char op='+';
        for(int i=0;i<s.size();)
        {
            int tmp=0;
            if(s[i]==' ')i++;
            else if(s[i]>='0'&&s[i]<='9')
            {
                while(i<s.size()&&(s[i]>='0'&&s[i]<='9'))
                    tmp=tmp*10+(s[i++]-'0');
                if(op=='+') v.push_back(tmp);
                else if(op=='-') v.push_back(-tmp);
                else if(op=='*')v.back()*=tmp;
                else v.back()/=tmp;
            }
            else op=s[i++];
        }
        int sum=0;
        for(auto&e:v)sum+=e;
        return sum;
    }
};

1.4 字符串解码

  1. 题⽬链接:394. 字符串解码
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(两个栈):
    算法思路:
    对于 3[ab2[cd]] ,我们需要先解码内部的,再解码外部(为了⽅便区分,使⽤了空格):
    • 3[ab2[cd]] -> 3[abcd cd] -> abcdcd abcdcd abcdcd
    在解码 cd 的时候,我们需要保存 3 ab 2 这些元素的信息,并且这些信息使⽤的顺序是从后往前,正好符合栈的结构,因此我们可以定义两个栈结构,⼀个⽤来保存解码前的重复次数 k (左括号前的数字),⼀个⽤来保存解码之前字符串的信息(左括号前的字符串信息)。
  4. C++代码
class Solution {
public:
    string decodeString(string s) 
    {
        stack<int> st1;
        stack<string> st2;
        for(int i=0;i<s.size();)
        {
            if(s[i]-'0'>=0&&s[i]-'0'<=9)
            {
                int tmp=0;
                while(i<s.size()&&(s[i]-'0'>=0&&s[i]-'0'<=9))
                {
                    tmp=tmp*10+(s[i++]-'0');
                }
                st1.push(tmp);
            }
            else if(s[i]=='['||(s[i]>=97&&s[i]<=122))
            {
                string tmp;
                if(s[i]=='[')
                {
                    tmp+='[';
                    st2.push(tmp);
                    i++;
                }
                else 
                {
                    while(i<s.size()&&(s[i]>=97&&s[i]<=122))
                    {
                        tmp+=s[i++];
                    }
                    st2.push(tmp);
                }
            }
            else
            {
                string str;
                while(st2.top()!="[")
                {
                    string tmp=st2.top();
                    st2.pop();
                    str.insert(0,tmp);
                }
                if(st2.top()=="[")st2.pop();//删除"]"
                int ret=st1.top();
                st1.pop();
                string ss;
                while(ret--)
                {
                    ss+=str;
                }
                st2.push(ss);
                i++;
            }
        }
        vector<string>v;
        string str;
        while(!st2.empty())
        {
            v.push_back(st2.top());
            st2.pop();
        }
        for(int i=v.size()-1;i>=0;i--)
        str+=v[i];
        return str;
    }
};

1.5 验证栈序列

  1. 题⽬链接:946. 验证栈序列
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(栈):
    算法思路:
    ⽤栈来模拟进出栈的流程。
    ⼀直让元素进栈,进栈的同时判断是否需要出栈。当所有元素模拟完毕之后,如果栈中还有元素,那么就是⼀个⾮法的序列。否则,就是⼀个合法的序列。
  4. C++代码
class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) 
    {
        stack<int> st;
        int i=0,n=popped.size();
        for(auto&e:pushed)
        {
            st.push(e);
            while(st.size()&&st.top()==popped[i])
            {
                st.pop();
                i++;
            }
        }
        return i==n;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小沈YO.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值