算法之栈(stack)

栈本身不是一个很难的数据结构, 但是对应的算法题有一定难度, 难在我们是否能想到这道题用栈解决. 如果知道用栈解决这道题, 那其实本质就是模拟.

题目1: 删除字符中的所有相邻重复项

cpp 复制代码
class Solution {
public:
    string removeDuplicates(string s) {
        stack<char> st;
        string ret;
        
        for(const auto& e: s)
        {
            if(st.empty())
                st.push(e);
            else if(e == st.top())
                st.pop();
            else
                st.push(e);
        }
        
        while(!st.empty())
        {
            ret += st.top();
            st.pop();
        }
        reverse(ret.begin(),ret.end());
        return ret;
    }
};

用栈最后把元素拷贝到字符串中, 最后还需要逆序一次, 可以直接用字符串模拟栈的行为即可:

cpp 复制代码
class Solution {
public:
    string removeDuplicates(string s) {
        string ret;
        for(const auto& e: s)
        {
            if(ret.length() == 0)
                ret += e;
            else if(ret.back() == e)
                ret.pop_back();
            else
                ret += e;
        }
        return ret;
    }
};

题目1.2 比较含退格的字符串

这题和题目1几乎一样, 用栈模拟即可.

cpp 复制代码
class Solution {
public:
    bool backspaceCompare(string s, string t) {
        string tmpS, tmpT;
        for(const auto& e : s)
        {
            if(!tmpS.empty() && e == '#')
            //e为#,栈不为空,就退格
                tmpS.pop_back();
            else if(e == '#')
            //如果e为#, tmpS为空, 就不用退格了
                continue;
            else
                tmpS += e;
        }

        //对T进行同样的操作
        for(const auto& e : t)
        {
            if(!tmpT.empty() && e == '#')
                tmpT.pop_back();
            else if(e == '#')
                continue;
            else
                tmpT += e;
        }

        return tmpS == tmpT;
    }
};

题目2:基本计算器 II

此题有两种思路, 比较麻烦的一种是中缀转后缀表达式, 然后后缀表达式进行计算, 基本计算器I 可以用这种思路解.

由于此题没有括号的运算, 只有加减乘除, 可以直接从左到右依次遍历, 将 或者 **通过乘除法计算后的值 ,**放入栈中, 然后依次出栈将结果累加即可, 具体分为:

  1. 符号是+/-, 该数是否被立即计算是不确定的, 先入栈等待, 如果是减则入栈一个负值, 因为最后的计算全是加法. 如果下一个符号仍是+-, 则前一个数就被保留至最终运算了, 比如2+3

  2. 符号是*/, 这是此题优先级最高的运算, 遇到它需要把栈顶正在"等待"的元素取出进行乘除法运算, 再放回栈里. 比如 2+ 3 * 4, 遇到4时取出栈顶的3, 计算为12压入栈中.

cpp 复制代码
class Solution {
public:
   
    int calculate(string s) {
        stack<int> st;
        char Op = '+';
        int left = 0, right = 0;
        int n = s.size();
        while(right < n)
        {
            //跳过空白
            if(s[right] == ' ')
                ++right;
            //数字
            else if(isdigit(s[right]))
            {
                //先把数字提取出来, 可能有多位
                int num = 0;
                while(right < n && isdigit(s[right]))
                    num = num*10 + (s[right++]-'0');
                if(Op == '+') st.push(num);
                else if(Op == '-') st.push(-num);
                else if(Op == '*')
                {
                    num = st.top() * num;
                    st.pop();
                    st.push(num);
                }
                else 
                {
                    num = st.top() / num;
                    st.pop();
                    st.push(num);
                }
            }
            else
                Op = s[right++];
        }

        int ret = 0;
        while(!st.empty())
        {
            ret += st.top();
            st.pop();
        }
        return ret;
    }
};

题目3: 字符串解码

此题思路要用到双栈, 由于我们需要从内向外解码字符串, 每次都要先解码内部[]的字符串, 层层向外.

从左到右扫描, 将扫描的内容分为四种情况:

  1. 数字num, 则压入数字栈中, 等待 ']', 作为字符串重复的次数

  2. '[', 将后面紧跟的(也可能没有)字符串压入字符串栈中, 等待']', 作为字符串重复的内容

  3. ']', 取出两个栈栈顶的元素, 开始重复. 将结果与**新栈顶的字符串合并,**因为内层解码的目的是把内容提供给外层作为外层字符串的一部分, 所以需要合并.

  4. 字符, 这时说明遇到了一个"裸"的字符串, 即只单纯重复一次, 同上面一样, 与栈顶字符串合并.

以一个复杂的例子为例: 3[z] 2[2[y]pq4[a]] ef

cpp 复制代码
class Solution {
public:
    string decodeString(string s) {
        stack<int> stNum;
        stack<string> stStr;
        stStr.push("");
        int i = 0, n = s.size();

        while (i < n) 
        {
            if (isdigit(s[i])) 
            {
                int tmpNum = 0;
                while (i < n && s[i] >= '0' && s[i] <= '9')
                    tmpNum = tmpNum * 10 + (s[i++] - '0');
                stNum.push(tmpNum);
            } 
            else if (s[i] == '[') 
            {
                ++i;
                string tmpStr;
                while (isalpha(s[i]))
                    tmpStr += s[i++];
                
                stStr.push(tmpStr);
            } 
            else if (s[i] == ']') 
            {
                int num = stNum.top();
                stNum.pop();

                string str = stStr.top();
                stStr.pop();

                while (num--)
                    stStr.top() += str;
                ++i;
            }
            else 
            {
                while (i < n && isalpha(s[i]))
                    stStr.top() += s[i++];
            }
        }

        return stStr.top();
    }
};

题目4: 验证栈序列

此题和数据结构做过的选择题很像, 不过验证是否能按照指定顺序出栈 .

思路都是一样的, 依次将pushed的元素入栈, 每入一个元素就检查一次poped栈是否能出栈, 而且要循环检查, 因为可能出了一个元素就能出一连串的元素. 最后所有元素都出栈则验证成功.

cpp 复制代码
class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        stack<int> st;
        int j = 0;
        for(const auto & e : pushed)
        {
            st.push(e);
            while(!st.empty() && st.top() == popped[j])
            {
                st.pop();
                ++j;
            }
        }
        return st.empty();
    }
};

暂完

相关推荐
heimeiyingwang9 天前
【深度学习加速探秘】Winograd 卷积算法:让计算效率 “飞” 起来
人工智能·深度学习·算法
时空自由民.9 天前
C++ 不同线程之间传值
开发语言·c++·算法
ai小鬼头9 天前
AIStarter开发者熊哥分享|低成本部署AI项目的实战经验
后端·算法·架构
小白菜3336669 天前
DAY 37 早停策略和模型权重的保存
人工智能·深度学习·算法
zeroporn9 天前
以玄幻小说方式打开深度学习词嵌入算法!! 使用Skip-gram来完成 Word2Vec 词嵌入(Embedding)
人工智能·深度学习·算法·自然语言处理·embedding·word2vec·skip-gram
亮亮爱刷题9 天前
飞往大厂梦之算法提升-7
数据结构·算法·leetcode·动态规划
_周游9 天前
【数据结构】_二叉树OJ第二弹(返回数组的遍历专题)
数据结构·算法
双叶8369 天前
(C语言)Map数组的实现(数据结构)(链表)(指针)
c语言·数据结构·c++·算法·链表·哈希算法
安全系统学习9 天前
【网络安全】DNS 域原理、危害及防御
算法·安全·web安全·网络安全·哈希算法
Cyrus_柯9 天前
C++(面向对象编程——继承)
开发语言·c++·算法·面向对象