代码随想录算法训练营第10天|150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素

LeetCode150

2025-01-31 21:05:49 星期五

题目描述:力扣150
文档讲解:代码随想录(programmercarl)150. 逆波兰表达式求值
视频讲解:《代码随想录》算法视频公开课:栈的最后表演! | LeetCode:150. 逆波兰表达式求值

代码随想录视频内容简记

梳理

  1. 一个for循环遍历字符串s

  2. 之后分别用if-else判断遍历的时数字还是计算符。如果是计算符,则弹出两个栈顶的元素进行计算之后(注意题目中说明了逆波兰表达式是合法的,所以不用担心对空栈进行操作),再压入栈中;如果是数字,则直接压入栈中

  3. 最后遍历结束,返回栈顶元素,释放内存即可

大致代码内容

  1. 在if判断然后向栈中压入元素时,需要注意num1和num2的顺序if (tokens[i] == "/") st.push(num2 / num1);,举个例子,["4","13","5","/","+"],写成num1num2的顺序写反了就是完全两个不一样的结果。这个千万要注意

  2. 定义了一个整型的数组,所以需要对其中的元素进行类型转换,可以使用C++标准库中的stoi()函数,转换为整型,还有一个stoll()函数可以转换为long long型。st.push(stoi(tokens[i]))

LeetCode测试

左闭右闭

点击查看代码
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> st;
        for (int i = 0; i < tokens.size(); i++) {
            // JiaoJiao
            if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {
                int num1 = st.top(); st.pop();
                int num2 = st.top(); st.pop();
                if (tokens[i] == "+") st.push(num2 + num1);
                if (tokens[i] == "-") st.push(num2 - num1);
                if (tokens[i] == "*") st.push(num2 * num1);
                if (tokens[i] == "/") st.push(num2 / num1);
            } else {
                st.push(stoi(tokens[i]));
            }
        }
        int result = st.top();
        st.pop();
        return result;
    }
};

LeetCode239

题目描述:力扣239
文档讲解:代码随想录(programmercarl)239. 滑动窗口最大值
视频讲解:《代码随想录》算法视频公开课:单调队列正式登场!| LeetCode:239. 滑动窗口最大值

代码随想录视频内容简记

题目设计就是要实现一个单调队列,来维护队列内的元素,目的就是要实现队列的单调递减或者单调递增。在本题中,我们就是要实现一个单调递减的队列,核心和难点就是如何设计对应的判断来维持这个单调递减的队列

梳理

注意要时刻维护单调队列出口处的元素为最大值

  1. 使用一个push()函数用于压入队列入口处(右边)的元素。将滑动窗口新增的元素记为k,其规则是如果在push的时候,单调队列前面所有小于该元素k的队列元素都需要被弹出。如果该元素k小于前面的队列元素数组,那么可以压入队列

  2. 使用一个pop()函数负责弹出队列出口处(左边)的元素。因为队列维护的就是一个最大值,所以每次在队列中需要pop()的元素都是滑动窗口的最大值。将滑动窗口移除的元素记为k,那么如果单调队列的出口元素和k相等,则可以弹出单调队列中的元素。

  3. 使用一个get_max_value()函数计算滑动窗口内的最大值,每次将单调队列的队头元素(出口是front,入口是back)进行弹出即可

大致代码内容

  1. 关于pop()函数,if (!queue.empty() && value == queue.front()) queue.pop_front()

  2. 关于push()函数,if (!queue.empty() && value > queue.back()) queue.pop_back()

  3. 关于get_max_value()函数,直接return queue.front()

LeetCode测试

这个题太复杂了,😵😵,第一次接触这个做法

点击查看代码
class Solution {
private:
    class MyQueue {
    public:
        deque<int> que;

        void pop(int value) {
            if (!que.empty() && que.front() == value) que.pop_front();
        }

        void push(int value) {
            while (!que.empty() && value > que.back()) que.pop_back();
            que.push_back(value);
        }

        int get_max_value() {
            return que.front();
        }
    };
    

public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        MyQueue que;
        vector<int> result;
        for (int i = 0; i < k; i++) {
            que.push(nums[i]);
        }
        result.push_back(que.get_max_value());
        for (int i = k; i < nums.size(); i++) {
            que.pop(nums[i - k]);
            que.push(nums[i]);
            result.push_back(que.get_max_value());
        }
        return result;
    }
};

LeetCode347

题目描述:力扣347
文档讲解:代码随想录(programmercarl)347.前 K 个高频元素
视频讲解:《代码随想录》算法视频公开课:优先级队列正式登场!大顶堆、小顶堆该怎么用?| LeetCode:347.前 K 个高频元素

代码随想录视频内容简记

首先是大顶堆和小顶堆,大顶堆每次pop()的元素是堆顶最大的元素,而小顶堆每次弹出的是堆顶最小的元素;本体要保留前K个高频元素,也就是前K个最大的元素,那么需要用到小顶堆,把每次的最小值弹出去

优先级队列,实现优先级队列的数据结构就是堆

梳理

  1. 首先用map这种数据结构来存储数组每个元素(key)和对应的频率(value)

  2. 之后定义一个小顶堆,需要手写一个比较函数,k哥说直接看网站上的写。然后对map进行遍历,在优先级队列中进行储存,如果队列的长度大于K,那么就进行弹出

  3. 因为最后的优先级队列进行输出,会得到一个从小到大的排列,所以还需要定义一个数组result,遍历优先级队列,将最后的结果反向添加到result中

  4. 最后返回result

大致代码内容

  1. for (map : it),这里的意思是:将map的每一个元素映射到it上进行遍历,if (que.size > k) que.pop()

  2. for (int i = k - 1; i > 0; i--),注意这里的初始条件是是k - 1result[i] = que.top().first这里对result进行反向添加。这里注意不能写成result.push_back(que.top().first);因为这行代码的本质还是按数组的索引顺序依次往后面添加

LeetCode测试

代码中关于小根堆的实现,创建优先级队列还有优先级队列的映射操作比较陌生,代码里还是有一些细节需要注意,比如在这里定义vector需要写清楚数组大小为kque.top().first的first后面没有括号这样等等

感觉这个题也不好写

点击查看代码
class Solution {
public:
    class mycomparison {
    public:
        // 实现小顶堆
        bool operator() (const pair<int, int>& lhs, const pair<int, int>& rhs) {
            return lhs.second > rhs.second;
        }
    };
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> map;
        for (int i = 0; i < nums.size(); i++) map[nums[i]]++;

        // 创建一个优先级队列,对value进行排序
        priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> que;

        for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++) {
            que.push(*it);
            if (que.size() > k) {
                que.pop();
            }
        }

        vector<int> result(k);
        for (int i = k - 1; i >= 0; i--) {
            result[i] = que.top().first;
            que.pop();
        }
        return result;
    }
};
posted on   bnbncch  阅读(1308)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示