《算法题讲解指南:优选算法-栈》--65.删除字符中的所有相邻重复项,66.比较含退格的字符串,67.基本计算器II,68.字符串解码,69.验证栈序列

🔥小叶-duck个人主页

❄️个人专栏《Data-Structure-Learning》《C++入门到进阶&自我学习过程记录》
《算法题讲解指南》--优选算法
《算法题讲解指南》--递归、搜索与回溯算法
《算法题讲解指南》--动态规划算法

未择之路,不须回头
已择之路,纵是荆棘遍野,亦作花海遨游


目录

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

题目链接:

题目描述:

题目示例:

解法(栈):

算法思路:

C++算法代码:

算法总结及流程解析:

66.比较含退格的字符串

题目链接:

题目描述:

题目示例:

解法(用数组模拟栈):

算法思路:

C++算法代码:

算法总结及流程解析:

67.基本计算器II

题目链接:

题目描述:

题目示例:

解法(栈):

算法思路:

C++算法代码:

算法总结及流程解析:

68.字符串解码

题目链接:

题目描述:

题目示例:

解法(两个栈):

算法思路:

C++算法代码:

算法总结及流程解析:

69.验证栈序列

题目链接:

题目描述:

题目示例:

解法(栈):

算法思路:

C++算法代码:

结束语


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

题目链接:

1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode)

题目描述:

题目示例:

解法(栈):

算法思路:

本题极像我们玩过的「开心消消乐」游戏,仔细观察消除过程,可以发现本题与我们之前做过的「括号匹配」问题是类似的。当前元素是否被消除,需要知道上一个元素的信息,因此可以用「栈」来保存信息。

但是,如果使用stack来保存的话,最后还需要把结果从栈中取出来。不如直接用「数组模拟一个栈」结构:在数组的尾部「尾插尾删」,实现栈的「进栈」和「出栈」。那么最后数组存留的内容,就是最后的结果。

C++算法代码:

cpp 复制代码
class Solution {
public:
    string removeDuplicates(string s) 
    {
        string ret;
        for(int i = 0; i < s.size(); i++)
        {
            // if(ret.size() == 0)
            // {
            //     ret.push_back(s[i]);
            // }
            // else
            // {
            //     if(ret.back() == s[i])
            //     {
            //         ret.pop_back();
            //     }
            //     else
            //     {
            //         ret.push_back(s[i]);
            //     }
            // }
            if(ret.size() && ret.back() == s[i])
            {
                ret.pop_back();
            }
            else
            {
                ret.push_back(s[i]);
            }
        }    
        return ret;
    }
};

算法总结及流程解析:

66.比较含退格的字符串

题目链接:

844. 比较含退格的字符串 - 力扣(LeetCode)

题目描述:

题目示例:

解法(用数组模拟栈):

算法思路:

由于退格的时候需要知道「前面元素」的信息,而且退格也符合「后进先出」的特性。因此我们可以使用「栈」结构来模拟退格的过程。

当遇到非 # 字符的时候,直接进栈;

当遇到 # 的时候,栈顶元素出栈。

为了方便统计结果,我们使用「数组」来模拟实现栈结构。

C++算法代码:

cpp 复制代码
class Solution {
public:
    bool backspaceCompare(string s, string t) 
    {
        vector<char> stack1;
        vector<char> stack2;
        for(int i = 0; i < s.size(); i++)
        {
            if(s[i] == '#' && stack1.size())
            {
                stack1.pop_back();
            }
            else if(s[i] != '#')
            {
                stack1.push_back(s[i]);
            }
        }
        for(int i = 0; i < t.size(); i++)
        {
            if(t[i] == '#' && stack2.size())
            {
                stack2.pop_back();
            }
            else if(t[i] != '#')
            {
                stack2.push_back(t[i]);
            }
        }
        return stack1 == stack2;
    }
};

算法总结及流程解析:

67.基本计算器II

题目链接:

227. 基本计算器 II - 力扣(LeetCode)

题目描述:

题目示例:

题目解析:

一定要认真看题目的提示,从提示中我们可以看到这道题:

只有「加减乘除」四个运算;

没有括号;

并且每一个数都是大于等于0的;

这样可以大大的「减少」我们需要处理的情况。

解法(栈):

算法思路:

由于表达式里面没有括号,因此我们只用处理「加减乘除」混合运算即可。根据四则运算的顺序,我们可以先计算乘除法,然后再计算加减法。由此,我们可以得出下面的结论:

当一个数前面是 '+' 号的时候,这一个数是否会被立即计算是「不确定」的,因此我们可以先压入栈中;

当一个数前面是 '-' 号的时候,这一个数是否被立即计算也是「不确定」的,但是这个数已经

和前面的-号绑定了,因此我们可以将这个数的相反数压入栈中;

当一个数前面是 '*' 号的时候,这一个数可以立即与前面的一个数相乘,此时我们让将栈顶的元素乘上这个数;

当一个数前面是 '/' 号的时候,这一个数也是可以立即被计算的,因此我们让栈顶元素除以这个数。

当遍历完全部的表达式的时候,栈中剩余的「元素之和」就是最终结果。

C++算法代码:

cpp 复制代码
class Solution {
public:
    int calculate(string s) 
    {
        vector<int> stack;
        int sum = 0;
        char op = '+';
        int i = 0;
        while(i < s.size())
        {
            if(s[i] >= '0' && s[i] <= '9')
            {
                //提取数字
                int num = 0;
                while(i < s.size() && s[i] >= '0' && s[i] <= '9')
                {
                    num = 10 * num + (s[i] - '0');
                    i++;
                }
                if(op == '+')
                {
                    stack.push_back(num);
                }
                else if(op == '-')
                {
                    stack.push_back(-num);
                }
                else if(op == '*')
                {
                    stack.back() *= num;
                }
                else
                {
                    stack.back() /= num;
                }
            }
            else if(s[i] == ' ')
            {
                i++;
            }
            else
            {
                op = s[i];
                i++;
            }
        }    
        for(int i = 0; i < stack.size(); i++)
        {
            sum += stack[i];
        }
        return sum;
    }
};

算法总结及流程解析:

68.字符串解码

题目链接:

394. 字符串解码 - 力扣(LeetCode)

题目描述:

题目示例:

解法(两个栈):

算法思路:

对于3[ab2[cd]],我们需要先解码内部的,再解码外部(为了方便区分,使用了空格):

3[ab2[cd]] -> 3[abcd cd] -> abcdcd abcdcd abcdcd

在解码 cd 的时候,我们需要保存 3ab2 这些元素的信息,并且这些信息使用的顺序是从后往
,正好符合栈的结构 ,因此我们可以定义两个栈结构 ,一个用来保存解码前的重复次数k (左括号

前的数字),一个用来保存解码之前字符串的信息(左括号后的字符串信息)。

C++算法代码:

cpp 复制代码
class Solution {
public:
    string decodeString(string s) 
    {
        stack<int> nums;
        stack<string> str;
        int i = 0;
        string tmp;
        while(i < s.size())
        {
            if(s[i] >= '0' && s[i] <= '9')
            {
                //提取数字
                int num = 0;
                while(s[i] >= '0' && s[i] <= '9')
                {
                    num = num * 10 + (s[i++] - '0');
                }
                nums.push(num);
            }
            else if(s[i] == '[')
            {
                string tmp;
                //将 [ 后面的字符串提取出来
                i++;
                while(s[i] >= 'a' && s[i] <= 'z')
                {
                    tmp += s[i++];
                }
                str.push(tmp);
            }
            else if(s[i] == ']')
            {
                int k = nums.top();
                nums.pop();
                tmp = str.top();
                str.pop();
                while(k--)
                {
                    //栈为空时则不能获取栈顶元素需要特判
                    if(str.empty())
                    {
                        str.push(tmp);
                    }
                    else
                    {
                        str.top() += tmp;
                    }
                }
                i++;
            }
            else
            {
                string tmp;
                //如果遇到字母(单独)则直接提取出来放入栈顶元素后面即可
                while(i < s.size() && s[i] >= 'a' && s[i] <= 'z')
                {
                    tmp += s[i++];
                }
                //栈为空时则不能获取栈顶元素需要特判
                if(str.empty())
                {
                    str.push(tmp);
                }
                else
                {
                    str.top() += tmp;
                }
            }
        } 
        return str.top();
    }
};

算法总结及流程解析:

69.验证栈序列

题目链接:

946. 验证栈序列 - 力扣(LeetCode)

题目描述:

题目示例:

解法(栈):

算法思路:

用栈来模拟进出栈的流程。

一直让元素进栈,进栈的同时判断是否需要出栈。当所有元素模拟完毕之后,如果栈中还有元素,那么就是一个非法的序列。否则,就是一个合法的序列。

C++算法代码:

cpp 复制代码
class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) 
    {
        vector<int> stack;
        int i = 0;
        for(auto e : pushed)
        {
            stack.push_back(e);
            while(stack.size() && i < popped.size() && stack.back() == popped[i])
            {
                stack.pop_back();
                i++;
            }
        }    
        return stack.size() == 0 ? true : false;
    }
};

结束语

到此,65.删除字符中的所有相邻重复项,66.比较含退格的字符串,67.基本计算器II,68.字符串解码,69.验证栈序列 这五道算法题就讲解完了。**删除字符串相邻重复项:使用数组模拟栈结构进行消消乐式消除;比较含退格的字符串:用栈模拟退格操作后比较结果;基本计算器II:利用栈处理加减乘除运算顺序;字符串解码:采用双栈分别存储重复次数和字符串信息;验证栈序列:直接模拟栈的进出过程进行验证。**希望大家能有所收获!

相关推荐
Q741_1472 小时前
每日一题 力扣 3653. 区间乘法查询后的异或 I 模拟 数学 位运算 C++ 题解
c++·数学·算法·leetcode·力扣·模拟
橘子编程2 小时前
编程语言全指南:从C到Rust
java·c语言·开发语言·c++·python·rust·c#
XiYang-DING2 小时前
【LeetCode】102.二叉树的层序遍历
算法·leetcode·职场和发展
艾莉丝努力练剑2 小时前
【Linux线程】Linux系统多线程(三):Linux线程 VS 进程,线程控制
java·linux·运维·服务器·c++·学习·ubuntu
计算机安禾2 小时前
【数据结构与算法】第33篇:交换排序(二):快速排序
c语言·开发语言·数据结构·数据库·算法·矩阵·排序算法
洛水水2 小时前
高性能网络编程:io_uring vs epoll、QPS测试工具实现与10道网络面试题解析
c++·udp·tcp·io_uring
沙雕不是雕又菜又爱玩2 小时前
leetcode第12、13、14、15题(C++)
c++·算法·leetcode
睡一觉就好了。2 小时前
C++多态
c++
汀、人工智能2 小时前
[特殊字符] 第50课:最大路径和
数据结构·算法·数据库架构·图论·bfs·最大路径和