代码随想录算法训练营Day11 栈与队列的其他题目

栈与队列的其他经典题目


Leetcode 150. 逆波兰表达式求值

题目链接:https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/

题目描述:给你一个字符串数组 tokens,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 [+][-][*][/]
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

题目解析:考虑用栈来模拟匹配的过程。遍历s的所有字符,如果遇到了运算符,就往前找两个数字进行计算,然后把结果放回去。

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> stk;
        for (auto& s : tokens) {
            if (s == "+" || s == "-" || s == "*" || s == "/") {
                int b = stk.top(); stk.pop();
                int a = stk.top(); stk.pop();
                if (s == "+") stk.push(a + b);
                else if (s == "-") stk.push(a - b);
                else if (s == "*") stk.push(a * b);
                else if (s == "/") stk.push(a / b);
            } else {
                stk.push(stoi(s));
            }
        }
        return stk.top();
    }
};

Leetcode 239. 滑动窗口最大值

题目链接:https://leetcode.cn/problems/sliding-window-maximum/description/

题目描述:给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值

题目解析:滑动窗口板子题。

先说一下滑动窗口维护最值的原理。用一个很通俗的比方,如果有一个选手比你年轻,并且他比你更强,那么你永远不可能超过他。

对应到滑动窗口中,就是:如果一个元素比你晚进入窗口,并且他比你更大,那么你在窗口里,永远不可能是最优的。

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> ans(n - k + 1);
        deque<int> q;

        // 枚举每个元素
        for (int i = 0; i < n; i ++) {
            // 1.进入窗口
            while (!q.empty() && nums[q.back()] <= nums[i]) {
                q.pop_back();
            }
            q.push_back(i);
            
            // 2.离开窗口
            int left = i - k + 1;
            if (q.front() < left) {
                q.pop_front();
            }
            // 3.记录答案
            if (left >= 0) {
                ans[left] = nums[q.front()];
            }
        }

        return ans;
    }
};

Leetcode 347. 前 K 个高频元素

题目链接:https://leetcode.cn/problems/top-k-frequent-elements/description/

题目描述:给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

题目解析:首先我们需要得到每个元素出现的频率,考虑用unordered_map<int, int>记录。然后考虑桶排序,我们每个桶的编号是元素出现的频率,然后存放的是哪个元素

// (法一:桶排序)
class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
      // cnt:记录频率
      // max_cnt:便于桶排序
      unordered_map<int, int> cnt;
      int max_cnt = 0;
      for (auto x : nums) {
          cnt[x] ++;
          max_cnt = max(max_cnt, cnt[x]);
      }

      // buckets:经典桶排序
      vector<vector<int>> buckets(max_cnt + 1);
      for (auto& [x, c] : cnt) {
          buckets[c].push_back(x);
      }

      // 从大桶往小桶记录答案
      vector<int> ans;
      for (int i = max_cnt; i >= 0 && ans.size() < k; i --) {
          ans.insert(ans.end(), buckets[i].begin(), buckets[i].end());
      }
      return ans;
  }
};

我们还有另一种思路。我们先记录所有元素的频率,然后用priority_queue<pii>维护,最后只需要找到前k个就可以了。

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        // 记录频率
        unordered_map<int, int> cnt;
        for (auto x : nums) {
            cnt[x] ++;
        }

        // 用priority_queue来维护小根堆
        // cmp:如果cmp(a, b)为真,那么a的优先级比b高
        // 但是因为是priority_queue,所以变成
        // “如果cmp(a, b)为真,那么a的优先级比b高”
        using pii = pair<int, int>;
        auto cmp = [&](const pii& a, const pii& b) {
            return a.second > b.second;
        };

        priority_queue<pii, vector<pii>, decltype(cmp)> pq(cmp); // 不要忘记构造的时候传(cmp)
        for (auto& [x, c] : cnt) {
            pq.emplace(x, c);
            // 只要k个最好的,大于k了,就从最差的开始丢
            if (pq.size() > k) {
                pq.pop();
            }
        }
        // 记录答案
        vector<int> ans(k);
        for (int i = 0; i < k; i ++) {
            auto [x, c] = pq.top();
            pq.pop();
            ans[i] = x;
        }
        return ans;
    }
};

顺带一提,这样的时间复杂度是O(nlogk)的,而法一是更优的O(n)做法。


之前集训贪心的时候,我一直不会用匿名函数的写法,用仿函数我觉得太麻烦了。搞得我都是把数据倒过来,然后用自带的排序……

posted @ 2025-08-31 22:46  Tangzy0121  阅读(448)  评论(0)    收藏  举报