算法学习打卡day41|栈和队列:栈和队列相互实现、括号匹配、逆波兰表达式、滑动窗口最大值问题、求前 K 个高频元素

栈和队列相互实现

力扣题目链接:用栈实现队列、用队列实现栈
题目描述:

  • 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
    实现 MyQueue 类:
    void push(int x) 将元素 x 推到队列的末尾
    int pop() 从队列的开头移除并返回元素
    int peek() 返回队列开头的元素
    boolean empty() 如果队列为空,返回 true ;否则,返回 false
  • 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
    实现 MyStack 类:
    void push(int x) 将元素 x 压入栈顶。
    int pop() 移除并返回栈顶元素。
    int top() 返回栈顶元素。
    boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

思路:

  • 用栈实现队列的思路是遇到 push 就放到stk1里,如果遇到pop那么就把stk1的元素一次存到stk2里,然后从stk2的栈顶pop,就可以实现先入先出了。
  • 用队列实现栈的思路是一个队列que1用来存储元素,用另外一个队列que2来备份元素,但要pop元素时,就把que1的元素都存到que2的元素里,然后把que1最后一个元素删掉就行。

代码实现:

  • 用栈实现队列
class MyQueue {
public:MyQueue() {}void push(int x) {stack1.push(x);}int pop() {int x = 0;if (!stack2.empty()) {x = stack2.top();stack2.pop();return x;}while (!stack1.empty()) {x = stack1.top();stack1.pop();stack2.push(x);}x = stack2.top();stack2.pop();return x;}int peek() {int result = this->pop();//降低代码耦合度stack2.push(result);return result;}bool empty() {return stack1.empty() && stack2.empty();}
private:stack<int> stack1; //用来压栈stack<int> stack2;  //从stack1出占,压入stack2就是栈顶元素了
};
  • 用队列实现栈
class MyStack {
public:queue<int> que1;MyStack() {}void push(int x) {que1.push(x);}int pop() {int size = que1.size();int x = 0;while (--size) {x = que1.front();que1.pop();que1.push(x);}int result = que1.front();que1.pop();return result;}int top() {int result = pop();que1.push(result);return result;}bool empty() {return que1.empty();}};

括号匹配

力扣题目链接

题目描述:
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。

有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。

示例 1
输入:s = “()”
输出:true
示例 2
输入:s = “()[]{}”
输出:true
示例 3
输入:s = “(]”
输出:false

思路:

  • 这道题因为所有的元素都是括号,所以,我们直接把符号压入栈中,然后遇到右括号就和栈顶元素比较,如果匹配不到(不匹配或栈为空都是无效)那么肯定是无效的。当字符串遍历完后如果栈非空,那么字符串也是无效的。
  • 另外奇数一定是无法匹配的,可以在开头判断一下。

代码实现:

bool isValid(string s) {if (s.size() % 2)   return false;   //奇数一定无法匹配stack<char> stk;for (char& i : s) {if (i == '{' || i == '(' || i == '[') {stk.push(i);//左括号入栈} else {if (stk.empty())    return false;//如果是右括号,但是此时栈空,说明右边多了直接returnif (i == ')') {if (stk.top() != '(')   return false;//匹配不到就return} else if (i == ']') {if (stk.top() != '[')   return false;} else {if (stk.top() != '{')   return false;}stk.pop();//匹配到了,别忘了pop}}return stk.empty();//不用单独if判断了,直接在这里判断就行}
  • 代码实现进行了一定的优化,遇到左括号可以直接存对应右括号,那么遇到右括号可以直接进行比较是否相同了。
bool isValid(string s) {if (s.size() % 2)   return false;   //奇数一定无法匹配stack<char> stk;for (char& i : s) {if (i == '{')   stk.push('}');//换个思路,存右括号,那么遇到右括号直接比较是否相等就行了else if (i == '(') stk.push(')');else if (i == '[')  stk.push(']');else if (stk.empty() || stk.top() != i) return false;//右边多了或者没匹配到else stk.pop();//匹配到了,别忘了pop}return stk.empty();//不用单独if判断了,直接在这里判断就行}
  • 应用场景:
    • 编译器在词法分析的过程中处理括号、花括号等这个符号的逻辑,就是使用了栈来进行匹配的。
    • linux的cd命令也涉及到栈对路径处理。
    • 函数调用时的调用栈。
    • 递归也会借助栈来实现,每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中。

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

力扣题目链接
题目描述:
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例:
输入:“abbaca”
输出:“ca”
解释:
例如,在 “abbaca” 中,我们可以删除 “bb” 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 “aaca”,其中又只有 “aa” 可以执行重复项删除操作,所以最后的字符串为 “ca”。

思路:

  • 这道题有两种写法,栈的实现思路比较简单。
  • 借助栈:如果栈为空或者当前元素和栈顶元素不相等,就入栈,如果相等就把栈顶元素删除,遍历结束后就得到了最终结果。注意:字符串和数组是天然的栈!!!
  • 双指针法: 双指针法就是原地移除元素了,定义一个left和right指针,别激动和普通的删除重复项还不一样,是慢指针和快指针一起走,而且不是right和left比较,而是right和left-1去比较。! 而一般双指针法是left在从0走,right从1走,
    • 只有当慢指针的前一个元素和当前值相等时再退一格,只有这样才能保证奇数时留一个,偶数时都干掉(奇数时和前一个元素不一样了)。
    • 然后赋值时不是++left而是left++了,因为如果是偶数,那就是回退,然后偶数序列右边界下一个元素一定和左边界前一个不相等,这时就left就直接覆盖都给删了,如果是奇数那在右边界的时候已经和左边界前一个元素不相等了,可以留一个

代码实现:

string removeDuplicates(string s) {string result;for (char& i : s) {if (result.empty() || i != result.back()) {result.push_back(i);continue;}  result.pop_back();}return result;}
  • 双指针法
string removeDuplicates(string s) {int left = 0, right = 0;for (right; right < s.size(); ++right) {if (left > 0 && s[left - 1] == s[right]) {left--;} else {s[left++] = s[right];}}s.resize(left);return s;}

逆波兰表达式

力扣题目链接
题目描述:
给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。

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

示例 1

输入:tokens = [“2”,“1”,“+”,“3”,“*”]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

思路:

  • 这个题很简单,遇到加减乘除就从栈里取两个元素,然后将计算结果再放入栈里即可,没有遇到运算符就把其他元素放入栈。

代码实现:

int evalRPN(vector<string>& tokens) {stack<int> stk;int num1, num2;for (string& s : tokens) {if (s == "+" || s == "-" || s == "*" || s == "/") {num1 = stk.top();stk.pop();num2 = stk.top();stk.pop();if (s == "+")   stk.push(num2 + num1);if (s == "-")   stk.push(num2 - num1);if (s == "*")   stk.push(num2 * num1);if (s == "/")   stk.push(num2 / num1);} else {stk.push(stoi(s));}}return stk.top();}

滑动窗口最大值问题

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

返回 滑动窗口中的最大值 。

示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
在这里插入图片描述

思路:

  • 这道题涉及到单调队列的应用,需要自己实现一个单调队列,什么是单调队列? 即让队列里的元素单调递增或者递减。
  • 我们这道题需要实现一个单调递减的队列,最大值在队列头部,这里采用deque实现,C++底层默认也是deque实现的,主要涉及到push和pop两个操作:
    • push:push的时候如果需要push的值比栈尾大时,就把尾部的值删掉(如果不用删除的情况,就存到另一个栈里,push后再放进去)直到push的value比尾部值小停止删除。
    • pop:pop的话,需要和队列的front元素比较,如果相等就pop(),否则不需要进行操作,因为最大值没有发生改变,不需要执行pop操作(其实在push的时候已经给它干掉了)。
    • front:这个就是返回队列开始的元素,记录窗口最大值。

代码实现:

class Solution {
public://定义单调队列class MyQueue {public:void push(int value) {while (!que.empty() && value > que.back()) {que.pop_back();}que.push_back(value);}void pop(int value) {if (!que.empty() && value == que.front()) {que.pop_front();}}int front() {return que.front();}private:deque<int> que;};vector<int> maxSlidingWindow(vector<int>& nums, int k) {MyQueue my_que;//先放入k - 1个元素for (int i = 0; i < k - 1; ++i) {my_que.push(nums[i]);}int i = k - 1;vector<int> results;//依次取最大值while (i < nums.size()) {my_que.push(nums[i]);results.push_back(my_que.front());my_que.pop(nums[i - k + 1]);i++; }return results;}
};

求前 K 个高频元素

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

示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]

思路:

  • 一般遇到前k个或者k个元素合并之类的都可以试着用优先级队列来解题,本题也是使用优先级队列。
  • 分为以下三步:
    1. 首先先统计数组所有元素出现的次数,使用哈希map
    2. 建立小根堆,一直维持k个最大元素即可,既然是要求高频元素为啥不用大根堆? 因为使用大根堆需要比较map中的所有元素,而我们本题只需要维持最大的k个元素即可,每次利用小根堆把最小的元素干掉。
    3. 输出优先级队列的元素。
  • 另外本体需要自定义优先级队列的cmp,由于第三个参数是个类参数,所以我们需要自己定义一个类。
  • 还有为什么左大于右就会建立小顶堆,而不是建立大顶堆?

例如我们在写快排的cmp函数的时候,return left>right 就是从大到小,return left<right 就是从小到大,优先级队列的定义正好反过来了,可能和源码实现有关。

代码实现:

class mycomparison {public:bool operator () (const pair<int, int>& a, const pair<int, int>& b) {return a.second > b.second;}}; vector<int> topKFrequent(vector<int>& nums, int k) {//统计次数unordered_map<int, int> maps;for (int& i : nums) {maps[i]++;}//建堆priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;for (auto& i : maps) {pri_que.push(i);if (pri_que.size() > k) {pri_que.pop();}}//输出结果vector<int> results;while (k--) {results.push_back(pri_que.top().first);pri_que.pop();}return results;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/133740.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无人机航迹规划:狐猴优化算法LO求解无人机路径规划MATLAB(可以修改起始点,地图可自动生成)

一、狐猴优化算法 狐猴优化算法&#xff08;Lemurs Optimizer&#xff0c;LO&#xff09;由Ammar Kamal Abasi等人于2022年提出&#xff0c;该算法模拟狐猴的跳跃和跳舞行为&#xff0c;具有结构简单&#xff0c;思路新颖&#xff0c;搜索速度快等优势。狐猴优化算法&#xff…

JavaScript 进阶问题列表,巩固自己的知识。

不定时更新 JavaScript 进阶问题列表 从基础到进阶&#xff0c;测试你有多了解 JavaScript&#xff0c;刷新你的知识&#xff0c;或者帮助你的 coding 面试&#xff01; &#x1f4aa; &#x1f680; 答案❤️ 1. 输出是什么&#xff1f; function sayHi() {console.log(na…

iSlide2024一款基于PPT的插件工具包含38个设计辅助功能

根据使用者情况表明iSlide 是一款拥有30W素材的PPT高效设计软件&#xff0c;可提高90%工作效率&#xff0c;现全球已有超过1400万使用者&#xff0c;智能排版原创高品模板可商用图形&#xff0c;真正摆脱PPT的束缚&#xff0c;把精力用在该用的地方。我们都明白islide插件功能特…

Vue 3 中,watch 和 watchEffect 的区别

结论先行&#xff1a; watch&#xff1a;需要指明要监听的数据&#xff0c;而且在回调函数中可以获取到属性变化的前后值&#xff1b; 适用于需要精确控制监视范围的情况&#xff1b;也就是需要针对特定数据变化执行操作。 watchEffect&#xff1a;不用指明监听哪个属性&…

python单元测试框架(继承、unittest参数化、断言、测试报告)

一、继承 继承能解决什么问题&#xff1f; unittest每个模块都要用到前提条件以及清理&#xff0c;如果有上百个模块&#xff0c;我们要改域名和浏览器&#xff0c;就会工作量很大特别麻烦&#xff0c;这时我们可以用继承的思想只用改一次 我们可以将前提和清理提出来单独放…

新登录接口独立版变现宝升级版知识付费小程序-多领域素材资源知识变现营销系统

源码简介&#xff1a; 资源入口 点击进入 源码亲测无bug&#xff0c;含前后端源码&#xff0c;非线传&#xff0c;修复最新登录接口 梦想贩卖机升级版&#xff0c;变现宝吸取了资源变现类产品的很多优点&#xff0c;摒弃了那些无关紧要的东西&#xff0c;使本产品在运营和变现…

MVC、MVP、MVVM区别

MVC、MVP、MVVM区别 MVC&#xff08;Model-View-Controller&#xff09; 。是一种设计模式&#xff0c;通常用于组织与应用程序的数据流。它通常包括三个组件&#xff1a;模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;和控制器&#xff08;Controller&…

TDengine 上榜 BenchCouncil 全球首个开源贡献榜

近日&#xff0c;Bench Council&#xff08;国际测试委员会&#xff09;公布了“世界首个开源贡献榜”&#xff0c;该榜单号称“只以贡献分高下”。值得一提的是&#xff0c;涛思数据、TDengine 上榜 BenchCouncil 发布的开源计算机系统机构榜、成果榜&#xff0c;TDengine 创始…

CDN策略好坏的重要性

CDN加速技术在今天的互联网世界中扮演着至关重要的角色&#xff0c;它可以显著提高网站和应用程序的性能&#xff0c;同时也有助于提供更好的安全性。然而&#xff0c;设定安全策略的好坏对CDN的影响是一个关键的议题&#xff0c;本文将深入探讨这个问题。 CDN&#xff08;内容…

2、Sentinel基本应用限流规则(2)

2.2.1 是什么 Sentinel 是阿里中间件团队开源的&#xff0c;面向分布式服务架构的轻量级高可用流量控制组件&#xff0c;主要以流量为切入点&#xff0c;从流量控制、熔断降级、系统负载保护等多个维度来帮助用户保护服务的稳定性。 2.2.2 基本概念 • 资源 (需要被保护的东西…

宝马——使用人工智能制造和驾驶汽车

德国汽车制造商宝马(BMW)每年在全球制造和销售250万台汽车&#xff0c;其品牌包括宝马、MINI和劳斯莱斯。 宝马汽车以其卓越的性能和对新技术的应用而著名&#xff0c;它是道路上最精致的汽车之一&#xff0c;并且和其竞争对手戴姆勒(Daimler)一样&#xff0c;在将自动驾驶汽车…

Redis中的Zset类型

目录 Zset的相关命令 zadd zrange zcard zcount zrevrange zrangebyscore zpopmax bzpopmax zpopmin和bzpopmin zrank zrevrank zscore zrem zremrangebyrank zremrangebyscore 操作集合间的命令 zinterstore和zunionstore 内部编码 Zset的应用场景 Zset表…

独立键盘接口设计(Keil+Proteus)

前言 软件的操作参考这篇博客。 LED数码管的静态显示与动态显示&#xff08;KeilProteus&#xff09;-CSDN博客https://blog.csdn.net/weixin_64066303/article/details/134101256?spm1001.2014.3001.5501实验&#xff1a;用4个独立按键控制8个LED指示灯。 按下k1键&#x…

Mysql进阶-视图篇

介绍 视图&#xff08;View&#xff09;是一种虚拟存在的表。视图中的数据并不在数据库中实际存在&#xff0c;行和列数据来自定义视图的查询中使用的表&#xff0c;并且是在使用视图时动态生成的。 通俗的讲&#xff0c;视图只保存了查询的SQL逻辑&#xff0c;不保存查询结果。…

Si4010 一款带有MCU SoC RF发射机芯片 无线遥控器

Si4010是一款完全集成的SoC RF发射机&#xff0c;带有嵌入式CIP-51 8051 MCU&#xff0c;专为1GHz以下ISM频带设计。该芯片针对电池供电的应用进行了优化&#xff0c;工作电压为1.8至3.6 V&#xff0c;待机电流小于10 nA的超低电流消耗。高功率放大器可提供高达10 dBm的输出功率…

手术训练系统项目

★ 手术训练系统项目 项目描述&#xff1a;手术训练系统&#xff0c;它提供了多项功能&#xff0c;包括账户登录与创建、数据库与账户管理、课程管理、小组管理、成绩统计、证书发布、训练和系统设置。 职责描述: 1、训练功能开发&#xff08;任务概述、任务指导、评分规则、评…

【数据结构】手撕单链表

目录 前言 1 链表 1.1 链表的概念及结构 1.2 链表的分类 1.2.1 单向或者双向 1.2.2 带头或者不带头 1.2.3 循环或者非循环 1.2.4 无头单向非循环链表 1.2.5 带头双向循环链表 2 链表的实现 2.1 结构 2.2 结点的创建 2.3 尾插 2.4 头插 2.5 尾删 2.6 头删 2.7 …

数据结构与算法之美学习笔记:17 | 跳表:为什么Redis一定要用跳表来实现有序集合?

目录 前言如何理解“跳表”&#xff1f;用跳表查询到底有多快&#xff1f;跳表是不是很浪费内存&#xff1f;高效的动态插入和删除跳表索引动态更新解答开篇内容小结 前言 本节课程思维导图&#xff1a; 二分查找底层依赖的是数组随机访问的特性&#xff0c;所以只能用数组来实…

2.求100-999之间的水仙花数

#include<stdio.h>void fun(void){int i,a,b,c;for(i100;i<1000;i) {ai%10;//个 b(i/10)%10;//十 ci/100;//百 if(ia*a*ab*b*bc*c*c)printf("%d ",i);}}int main(){fun();return 0;}

STM32 GPIO 描述

一、GPIO功能描述 每个GPIO端口有两个32位配置寄存器(GPIOx_CRL&#xff0c;GPIOx_CRH) &#xff0c;两个32位数据寄存器 (GPIOx_IDR和GPIOx_ODR) &#xff0c;一个32位置位/复位寄存器(GPIOx_BSRR)&#xff0c;一个16位复位寄存器(GPIOx_BRR)和一个32位锁定寄存器(GPIOx_LCKR…