代码随想录算法训练营第12天 | 第五章 栈与队列part02


今日记录


150.逆波兰表达式求值

Leetcode链接

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
注意:
有效的算符为 ‘+’、‘-’、‘*’ 和 ‘/’ 。
每个操作数(运算对象)都可以是一个整数或者另一个表达式。
两个整数之间的除法总是 向零截断 。
表达式中不含除零运算。
输入是一个根据逆波兰表示法表示的算术表达式。
答案及所有中间计算结果可以用 32 位 整数表示。

逆波兰表达式:是一种后缀表达式(运算符写在后面) 用栈来实现:遇到数字则入栈;遇到运算符则取出栈顶的两个元素进行运算再压入栈中 ;

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<long long> st;
        for (int i = 0; i < tokens.size(); i++) {
            if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" ||
                tokens[i] == "/") {
                long long num1 = st.top();
                st.pop();
                long long 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(stoll(tokens[i])); // 将字符串str转成 long long 整数
            }
        }
        int result = st.top();
        st.pop();
        return result;
    }
};

239.滑动窗口最大值

Leetcode链接

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

使用队列,将窗口里的元素放入,随着窗口移动,队列加入新元素,前面的元素也出队。
queue que;
窗口移动,先que.pop()移除元素,que.push()加入新元素, que.front()

class Solution {
private:
    class Myqueue {
    public:
        deque<int> que; // 一个双向队列
        // pop函数实现:因为比队列出口的元素已经在push函数里被弹出了,所以除非新加入元素等于队列出口元素,否则不用做任何操作
        void pop(int value) {
            if (!que.empty() && value == que.front()) { // 返回队列头部的元素
                que.pop_front(); // 移除队列前端的元素
            }
        }
        // push函数实现:当新加入的元素比队列入口元素大,将入口元素一个一个弹出直到比入口元素小,保证了弹出顺序是从小到大(如果此时新加入的元素比队列出口的元素还大,一直弹出到队列出口的元素也被弹出)
        void push(int value) {
            while (!que.empty() && value > que.back()) {
                que.pop_back();
            }
            que.push_back(value);
        }

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

public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        Myqueue que;
        vector<int> result;
        for (int i = 0; i < k; i++) { // 滑动窗口值为k,先将前k个值放入
            que.push(nums[i]);
        }
        result.push_back(
            que.front()); // result将前k个最大值记录:向容器末尾添加值
        for (int i = k; i < nums.size(); i++) {
            que.pop(nums[i - k]); // 移除前面的值
            que.push(nums[i]);
            result.push_back(que.front());
        }
        return result;
    }
};

347.前K个高频元素

Leetcode链接

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

思路

这道题目主要涉及到如下三块内容:
1.要统计元素出现频率 —— map可以实现
2.对频率排序 —— 优先级队列 priority_queue
3.找出前K个高频元素

优先级队列 priority_queue

就是一个披着队列外衣的堆,因为优先级队列对外接口只是从队头取元素,从队尾添加元素,再无其他取元素的方式,看起来就是一个队列。
而且优先级队列内部元素是自动依照元素的权值排列。

什么是堆呢?
堆是一棵完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子的值。 如果父亲结点是大于等于左右孩子就是大顶堆,小于等于左右孩子就是小顶堆。
大顶堆(堆头是最大元素),小顶堆(堆头是最小元素),如果懒得自己实现的话,就直接用priority_queue(优先级队列)就可以了,底层实现都是一样的,从小到大排就是小顶堆,从大到小排就是大顶堆。

我们要用小顶堆,因为要统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素。

定义:

priority_queue< type, container, function>

这三个参数,后面两个可以省略,第一个不可以。其中:
type:数据类型;
container:实现优先队列的底层容器,必须是可随机访问的容器,例如vector、deque,而不能使用list;
function:元素之间的比较方式;
在STL中,默认情况下(不加后面两个参数)是以vector为容器,以 operator< 为比较方式,所以在只使用第一个参数时,优先队列默认是一个最大堆,每次输出的堆顶元素是此时堆中的最大元素。

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; // map<nums[i],对应出现的次数>
        for (int i = 0; i < nums.size(); i++) {
            map[nums[i]]++;
        }

        // 对频率排序
        // 定义一个小顶堆,大小为k
        priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;

        // 用固定大小为k的小顶堆,扫面所有频率的数值
        for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++) {
            pri_que.push(*it);
            if (pri_que.size() > k) { // 如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
                pri_que.pop();
            }
        }

        // 找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
        vector<int> result(k);
        for (int i = k - 1; i >= 0; i--) {
            result[i] = pri_que.top().first;
            pri_que.pop();
        }
        return result;

    }
};

总结

代码随想录算法训练营第9|队列part01 第五章 队列part01,,用模拟队列,用队列模拟,字符匹配括号匹配 阅读详情

相关推荐

代码随想录算法训练营| 队列 Part 1+2

代码代码随想录算法训练营| 队列 Part 1+2。

Wzlzlzl的博客 878

代码随想录算法训练营第10|队列part02

学习了大顶堆,优先队列,遍历逆波兰表达式,stoll 等东西。

zxjiaya的博客 847

代码随想录算法训练营| 第五章 队列part01

的简单介绍:在C++中,stack是标准模板库(STL)中提供的一种数据结构,表示(stack),它通常用于后进先出(LIFO)的数据管理。: 这个操作用于将元素压入顶(即入操作)。例如,如果你有一个,你可以通过将整数5压入st的顶部。: 这个操作用于从顶移除元素(即出操作)。例如,如果你有一个非空的st,通过st.pop();将移除顶的元素。: 这个操作返回顶元素的引用,但不会移除它。这可以让你访问顶的元素而不改变的内容。例如,如果你有一个st,你可以通过st.top();

zhuanshu_ID_的博客 1015

代码随想录算法训练营第十|队列part02

LeetCode 150 逆波兰表达式求值 LeetCode 239 滑动窗口最大值 LeetCode 347 前k个高频元素

欢迎光临花开富贵的博客 814

代码随想录算法训练营 Day10 | 队列 Part 1

本文系统梳理了队列的核心概念及应用。(LIFO)队列(FIFO)在实现上可通过数组或链表完成,二者可相互转换:实现队列需两个分别处理入队出队,队列实现则需重新入队操作。重点讲解了在解决括号匹配(LeetCode 20)和相邻重复项删除(LeetCode 1047)问题的应用思路,通过维护结构实现字符匹配消除。文中提供了Python实现代码,并指出常见错误:如未处理空/队列、括号类型不匹配等边界情况。最后强调这些数据结构在函数调用、进程调度等系统级应用中的重要性,建议根据具体场景选择合适

m0_52918393的博客 1338

代码随想录算法训练营第10 | 第五章 队列part01

提示:这里对文章进行总结:例如:以上就是今要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

monoki的博客 939

代码随想录算法训练营第11| 队列part02

1047. 删除字符串中的所有相邻重复项。150. 逆波兰表达式求值。

qq_34377938的博客 565

[代码随想录算法训练营Day10 队列Part1]

,在SGI版本的STL中(SGI STL 由Silicon Graphics Computer Systems公司参照HP STL实现),默认stack的底层是由双端队列deque实现的。也可以人为指定其他实现方式,比如用list 或者vector。so C++中 stack并不是一个容器,它是标准模版库STL提供的一种容器配接器(也就是对容器的接口进行了改装,类似,他也是个容器适配器。使用列表是最简单的方法~

yangxue_miao的博客 959

算法训练营day 10- 队列part1

leetcode232 用实现队列的操作看到题目的第一思路:暂无代码随想录之后的想法和总结:- 初始化两个in和out,出队直接就往in压,出队先检查out里面有没有元素,有的话out的顶就是队首,否则就先把in里面的元素弹出压入到out中。这样就能保证out的顶始终都是队首,in的顶始终都是队尾。- 理解这个解法的关键在于,这样就维持了输出顶是队列开头的定义。stack_intostack_outstack_instack_out遇到的困难:1 peek函数-peek。

Xyyyy12333的博客 845

代码随想录算法训练营第10 | 队列part01

本文总结了队列的基础知识及实现方式。遵循LIFO(后进先出)原则,队列遵循FIFO(先进先出)原则,两者都不支持遍历功能。通过C#代码示例展示了Stack和Queue的基本操作(Push/Pop和Enqueue/Dequeue)。文章强调在工业级代码开发中应避免复制粘贴,提倡抽象复用功能相近的代码。最后提到LeetCode第232题"用实现队列"的实践,体现了数据结构转换的应用。这些内容为算法训练提供了基础理论支持和实践指导。

such_ordinary的博客 259

代码随想录算法训练营第11|队列part02

小顶堆的实现需要三个参数 第一个是存的内容 第二个是底层容器 第三个是比较的类。用双端队列来实现,可以访问队尾元素,队首存储的是当前窗口元素的最大值的索引。代码随想录网站用long long型 longlong型8字节。队尾进出队:dq.push_back()150. 逆波兰表达式求值。239. 滑动窗口最大值。

xindafu的博客 266

代码随想录算法训练营Day11 | 队列 Part 2

本文系统梳理了队列和堆三种数据结构的核心特性应用。(LIFO)适用于括号匹配、逆波兰表达式等回溯场景;队列(FIFO)用于滑动窗口、BFS等顺序处理问题;堆(优先级队列)则能高效解决TopK、中位数查找等最值维护问题。文章通过LeetCode经典题目(如150、239、347题)展示了具体实现方法,并总结了常见易错点(如空操作、边界处理等),同时提出数据结构选择的依据:根据问题特性(回溯/顺序/最值)选择对应结构。最后强调了多语言实现差异和性能优化技巧,为算法实践提供了系统性指导。

m0_52918393的博客 1164

算法训练营 Day11 - 队列part02

简单的一句话规则:遇到数字就存起来,遇到符号就把最近存的两个数字拿出来算,算完把结果放回去。我们平时写,符号在数字中间。逆波兰式写成2 1 + 3 *,符号在数字后面。为什么要这么写?这对计算机非常友好,因为不需要括号,也不需要管乘除法优先于加减法,只要按照顺序读下去就能算出来。在这道题中,我们需要维护一个队列,这个队列内部的元素必须保持从大到小的顺序。队头 (Front):永远保存当前窗口内的最大值。队尾 (Back):保存可能成为未来最大值的候补元素。为了维持这个特性,我们在push和pop。

2301_80733560的博客 632

代码随想录算法训练营Day10|队列Part1

本文摘要: 总结了队列的基本概念及Python实现方式。(先进后出)可用list或deque实现,队列(先进先出)推荐使用deque以提高效率。通过LeetCode三道经典题目展示了队列的应用场景:232题用双模拟队列操作,225题用双端队列实现功能,20题利用结构解决括号匹配问题。文中详细分析了各题解题思路,并提供了Python代码实现,特别注意了不同数据结构操作的时间复杂度差异。文章还介绍了Python列表切片操作技巧。

Lspeak的博客 592

代码随想录算法训练营Day11|队列Part2

遍历逆波兰表达式存储至,遇到运算符,则pop两个数值参运算(先pop出的值放在运算符的后面参运算),运算后的结果再存储至,循环以上操作。注意:当滑动窗口向后移动时,需要比较【单调队列中的首值】是否和【滑动窗口后移前的首值】相同,若相同,则需将单调队列中的首值popleft出。对元素出现的频率进行排序,可利用map(key存储元素,value存储元素出现次数)进行存储。比较,去除队列中比当前值小的值,保证队列永远是单减的。,大顶堆是根节点最大的元素,小顶堆是根节点最小的元素。数据结构,该类数据结构。

Lspeak的博客 349

代码随想录训练营 Day10打卡 队列 part01 232.用实现队列 225.用队列实现 20. 有效的括号 1047. 删除字符串中的所有相邻重复项

代码随想录训练营 Day10打卡 队列 part01 232.用实现队列 225.用队列实现 20. 有效的括号 1047. 删除字符串中的所有相邻重复项

qq_42952637的博客 1076

代码随想录算法训练营 | 队列part01

你所使用的语言也许不支持队列。你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。请你仅使用两个队列实现一个后入先出(LIFO)的,并支持普通的全部四种操作(push、top、pop 和 empty)。你可以使用 list 或者 deque(双端队列)来模拟一个,只要是标准的操作即可。给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。pop元素时,将_que1的头部的元素(除了最后一个元素外),重新添加到队尾。

Fern_v的博客 650

代码随想录算法训练营第九|队列part01

仅使用两个实现先入先出队列队列应当支持一般队列支持的所有操作(push、pop、peek、empty):实现 MyQueue 类:void push(int x) 将元素 x 推到队列的末尾int pop() 从队列的开头移除并返回元素int peek() 返回队列开头的元素boolean empty() 如果队列为空,返回 true;

欢迎光临花开富贵的博客 859

leetcode 56合并区间

这道题你可以把它压缩成一个非常好记的思路:先排序,再逐个比较;能合并就扩右边界,不能合并就加入答案。具体来说,先用: 把所有区间按照左端点从小到大排序。排序之后,我们只需要拿“当前区间”和 里最后一个已经合并好的区间比较。如果: 说明前一个区间的右端点比当前区间左端点还小,二者没有重叠: 所以直接: 如果不满足: 那就说明: 两个区间重叠,例如: 此时左端点不用动,只需要把右端点扩大: 所以整道题可以记成: 这道题容易忘的函数/语法 含义:对整个 排序。对于:

qq_63176310的博客 224
上一篇: 代码随想录算法训练营第10天 | 第五章 栈与队列part01
下一篇: 代码随想录算法训练营第13天 | 第六章 二叉树part01
monoki
博客等级 码龄7年 251粉丝 · 42原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值