• 代码随想录笔记--栈与队列篇


    目录

    1--用栈实现队列

    2--用队列实现栈

    3--有效的括号

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

    5--逆波兰表达式求值

    6--滑动窗口的最大值

    7--前k个高频元素


    1--用栈实现队列

    利用两个栈,一个是输入栈,另一个是输出栈

    1. #include
    2. #include
    3. class MyQueue {
    4. public:
    5. MyQueue() {}
    6. void push(int x) {
    7. in_stk.push(x);
    8. }
    9. int pop() {
    10. if(out_stk.empty()){
    11. while(!in_stk.empty()){
    12. out_stk.push(in_stk.top());
    13. in_stk.pop();
    14. }
    15. }
    16. int tmp = out_stk.top();
    17. out_stk.pop();
    18. return tmp;
    19. }
    20. int peek() {
    21. if(out_stk.empty()){
    22. while(!in_stk.empty()){
    23. out_stk.push(in_stk.top());
    24. in_stk.pop();
    25. }
    26. }
    27. return out_stk.top();
    28. }
    29. bool empty() {
    30. if(out_stk.empty() && in_stk.empty()) return true;
    31. else return false;
    32. }
    33. private:
    34. std::stack<int> in_stk, out_stk;
    35. };
    36. int main(int argc, char* argv[]){
    37. MyQueue Queue;
    38. Queue.push(1);
    39. Queue.push(2);
    40. Queue.push(3);
    41. std::cout << Queue.pop() << std::endl;
    42. std::cout << Queue.peek() << std::endl;
    43. return 0;
    44. }

    2--用队列实现栈

    主要思路:

            弹出栈顶元素时,需要将队列前 size - 1 个元素先弹出再重新加入到队列中;

    1. #include
    2. #include
    3. class MyStack {
    4. public:
    5. MyStack() {}
    6. void push(int x) {
    7. q.push(x);
    8. }
    9. int pop() {
    10. int size = q.size();
    11. for(int i = 1; i <= size - 1; i++){
    12. q.push(q.front());
    13. q.pop();
    14. }
    15. int tmp = q.front();
    16. q.pop();
    17. return tmp;
    18. }
    19. int top() {
    20. int size = q.size();
    21. for(int i = 1; i <= size - 1; i++){
    22. q.push(q.front());
    23. q.pop();
    24. }
    25. int tmp = q.front();
    26. q.pop();
    27. q.push(tmp);
    28. return tmp;
    29. }
    30. bool empty() {
    31. return q.empty();
    32. }
    33. private:
    34. std::queue<int> q;
    35. };
    36. int main(int argc, char* argv[]){
    37. MyStack stk;
    38. stk.push(1);
    39. stk.push(2);
    40. stk.push(3);
    41. std::cout << stk.pop() << std::endl;
    42. std::cout << stk.top() << std::endl;
    43. return 0;
    44. }

    3--有效的括号

    主要思路:

            基于栈,遇到左括号,入栈对应的右括号。遇到右括号,判断当前栈顶元素是否与右括号相等,相等则表示之前曾遇到对应的左括号,表明匹配成功并弹出栈顶元素,否则返回 false;

            最后判断栈是否为空,即是否有未匹配的左括号;

    1. #include
    2. #include
    3. #include
    4. class Solution {
    5. public:
    6. bool isValid(std::string s) {
    7. std::stack<char> stk;
    8. for(int i = 0; i < s.length(); i++){
    9. if(s[i] == '(') stk.push(')');
    10. else if(s[i] == '[') stk.push(']');
    11. else if(s[i] == '{') stk.push('}');
    12. else{
    13. if(stk.empty()) return false;
    14. else if(stk.top() != s[i]) return false;
    15. else stk.pop(); // 匹配
    16. }
    17. }
    18. return stk.empty();
    19. }
    20. };
    21. int main(int argc, char* argv[]){
    22. std::string test = "()[]{}";
    23. Solution S1;
    24. bool res = S1.isValid(test);
    25. if(res) std::cout << "true" << std::endl;
    26. else std::cout << "false" << std::endl;
    27. return 0;
    28. }

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

    主要思路:

            基于栈,遍历字符串,判断当前字符与栈顶元素是否相同,相同则弹出栈顶元素,否则入栈;

            最后遍历栈,将栈内的元素重构为字符串,需注意顺序;

    1. #include
    2. #include
    3. #include
    4. class Solution {
    5. public:
    6. std::string removeDuplicates(std::string s) {
    7. std::stack<char> stk;
    8. for(int i = 0; i < s.length(); i++){
    9. if(stk.empty() || stk.top() != s[i]){
    10. stk.push(s[i]);
    11. }
    12. else{ // s[i] == stk.top()
    13. stk.pop();
    14. }
    15. }
    16. std::string res;
    17. while(!stk.empty()){
    18. res = stk.top() + res;
    19. stk.pop();
    20. }
    21. return res;
    22. }
    23. };
    24. int main(int argc, char* argv[]){
    25. std::string test = "abbaca";
    26. Solution S1;
    27. std::string res = S1.removeDuplicates(test);
    28. std::cout << res << std::endl;
    29. return 0;
    30. }

    5--逆波兰表达式求值

    主要思路:

            基于栈,遍历字符串数组,当遇到数字时将数字压入栈中,当遇到运算符时,将栈顶的两个元素取出来进行运算,并将运算结果重新压入栈中;

            需注意运算顺序,即第二个出栈的 num2 作为运算符的左侧元素;

    1. #include
    2. #include
    3. #include
    4. #include
    5. class Solution {
    6. public:
    7. int evalRPN(std::vector& tokens) {
    8. std::stack<int> stk;
    9. for(int i = 0; i < tokens.size(); i++){
    10. if(tokens[i] != "+" && tokens[i] != "-" && tokens[i] != "*" && tokens[i] != "/"){
    11. stk.push(std::stoi(tokens[i]));
    12. continue;
    13. }
    14. int num1 = stk.top();
    15. stk.pop();
    16. int num2 = stk.top();
    17. stk.pop();
    18. if(tokens[i] == "+"){
    19. int num3 = num2 + num1;
    20. stk.push(num3);
    21. continue;
    22. }
    23. else if(tokens[i] == "-"){
    24. int num3 = num2 - num1;
    25. stk.push(num3);
    26. continue;
    27. }
    28. else if(tokens[i] == "*"){
    29. int num3 = num2 * num1;
    30. stk.push(num3);
    31. continue;
    32. }
    33. else{
    34. int num3 = num2 / num1;
    35. stk.push(num3);
    36. continue;
    37. }
    38. }
    39. return stk.top();
    40. }
    41. };
    42. int main(int argc, char* argv[]){
    43. // tokens = ["2","1","+","3","*"]
    44. std::vector test = {"2", "1", "+", "3", "*"};
    45. Solution S1;
    46. int res = S1.evalRPN(test);
    47. std::cout << res << std::endl;
    48. return 0;
    49. }

    6--滑动窗口的最大值

    主要思路:

            维护一个双端队列,队列里的元素存储的是可能成为最大值的元素,对于当前滑动窗口,其最大值为队头元素;

            当移动滑动窗口时,需要判断当前移出窗口的元素是否是队头元素,如果是则需先将队头元素弹出(因为该元素已经离开了滑动窗口,相当于失效);

            之前本题的解法是存储元素的索引(之前的解法),这样可以避免重复元素的出现;但现在本题的解法是存储元素,所以一个细节是需要避免错误移除重复元素的问题,具体可以推导例子:[-7,-8,7,5,7,1,6,0];

    1. #include
    2. #include
    3. #include
    4. class Solution {
    5. public:
    6. std::vector<int> maxSlidingWindow(std::vector<int>& nums, int k) {
    7. std::deque<int> q; // 存储可能成为最大值的元素
    8. std::vector<int> res;
    9. // 初始化第一个滑动窗口
    10. for(int i = 0; i < k; i++){
    11. // 不能取等于号的原因是可能会出现相等的数,例如下例
    12. // [-7,-8,7,5,7,1,6,0] 出现了两个7,取=号会误弹出第2个7
    13. while(!q.empty() && q.back() < nums[i]){
    14. q.pop_back();
    15. }
    16. q.push_back(nums[i]);
    17. }
    18. res.push_back(q.front());
    19. // 遍历更新
    20. for(int i = k; i < nums.size(); i++){
    21. // 移除滑动窗口左边界的元素
    22. if(nums[i-k] == q.front()) q.pop_front();
    23. // 把不可能成为最大值的元素从队列中移出
    24. while(!q.empty() && q.back() < nums[i]){
    25. q.pop_back();
    26. }
    27. q.push_back(nums[i]);
    28. res.push_back(q.front()); // 记录当前滑动窗口的最大值
    29. }
    30. return res;
    31. }
    32. };
    33. int main(int argc, char* argv[]){
    34. std::vector<int> test = {1, 3, -1, -3, 5, 3, 6, 7};
    35. int k = 3;
    36. Solution S1;
    37. std::vector<int> res = S1.maxSlidingWindow(test, k);
    38. for(auto v : res) std::cout << v << " ";
    39. std::cout << std::endl;
    40. return 0;
    41. }

    7--前k个高频元素

    主要思路:

            维护一个优先队列(小顶堆),里面存储 k 个元素及其出现的次数;

    1. #include
    2. #include
    3. #include
    4. #include
    5. class Solution {
    6. public:
    7. std::vector<int> topKFrequent(std::vector<int>& nums, int k) {
    8. std::map<int, int> m;
    9. for(int i = 0; i < nums.size(); i++){
    10. m[nums[i]] += 1;
    11. }
    12. // 小顶堆
    13. std::priority_queueint, int>, std::vectorint, int>>, mycompare> pri_q;
    14. for(auto it = m.begin(); it != m.end(); it++){
    15. pri_q.emplace(*it);
    16. if(pri_q.size() > k) pri_q.pop(); // 始终维护 k 个 pair 对
    17. }
    18. // 倒叙输出k个高频元素
    19. std::vector<int> res(pri_q.size(), 0);
    20. for(int i = pri_q.size() - 1; i>=0; i--){
    21. res[i] = pri_q.top().first;
    22. pri_q.pop();
    23. }
    24. return res;
    25. }
    26. class mycompare{
    27. public:
    28. bool operator()(std::pair<int, int>& item1, std::pair<int, int>& item2){
    29. return item1.second > item2.second;
    30. }
    31. };
    32. };
    33. int main(int argc, char* argv[]){
    34. // nums = [1,1,1,2,2,3], k = 2
    35. std::vector<int> test = {1, 1, 1, 2, 2, 3};
    36. int k = 2;
    37. Solution S1;
    38. std::vector<int> res = S1.topKFrequent(test, k);
    39. for(auto item : res) std::cout << item << " ";
    40. std::cout << std::endl;
    41. return 0;
    42. }

  • 相关阅读:
    Spring之BeanFactory
    自定义注解打印日志与耗时
    仓库管理系统到底是什么?有必要专门买一个吗?
    Linux无文件木马程序渗透测试复现
    Vue教学19:Element UI组件深入探索,构建精致的Vue应用界面
    STM32F103学习笔记(六) RTC实时时钟(应用篇)
    8-事件组或标志
    人工智能第2版学习——博弈中的搜索2
    机器学习数据挖掘十大经典算法 数学建模常用算法
    抖音seo源码--开源,支持二开不加密
  • 原文地址:https://blog.csdn.net/weixin_43863869/article/details/132626708