【优选算法之队列+宽搜/优先级队列】No.14--- 经典队列+宽搜/优先级队列算法

文章目录

  • 前言
  • 一、队列+宽搜示例:
    • 1.1 N 叉树的层序遍历
    • 1.2 ⼆叉树的锯⻮形层序遍历
    • 1.3 ⼆叉树最⼤宽度
    • 1.4 在每个树⾏中找最⼤值
  • 二、优先级队列(堆)示例:
    • 2.1 最后⼀块⽯头的重量
    • 2.2 数据流中的第 K ⼤元素
    • 2.3 前 K 个⾼频单词
    • 2.4 数据流的中位数


前言

在这里插入图片描述

👧个人主页:@小沈YO.
😚小编介绍:欢迎来到我的乱七八糟小星球🌝
📋专栏:优选算法
🔑本章内容:队列+宽搜/优先级队列
记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~


一、队列+宽搜示例:

1.1 N 叉树的层序遍历

  1. 题⽬链接:429. N 叉树的层序遍历
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法:
    算法思路:
    层序遍历即可~
    仅需多加⼀个变量,⽤来记录每⼀层结点的个数就好了。
  4. C++代码
/*
// Definition for a Node.
class Node {
public:int val;vector<Node*> children;Node() {}Node(int _val) {val = _val;}Node(int _val, vector<Node*> _children) {val = _val;children = _children;}
};
*/class Solution {
public:vector<vector<int>> levelOrder(Node* root) {vector<vector<int>> vv;vector<int> v;if(root==nullptr)return vv;queue<Node*> q;q.push(root);while(!q.empty()){int sz=q.size();//统计本层节点个数while(sz--){Node* tmp=q.front();v.push_back(tmp->val);q.pop();for(auto&e:tmp->children)//逐次加入孩子节点{if(e!=nullptr)q.push(e);}}vv.push_back(v);v.clear();}return vv;}
};

1.2 ⼆叉树的锯⻮形层序遍历

  1. 题⽬链接:103. ⼆叉树的锯⻮形层序遍历
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(层序遍历):
    算法思路:
    在正常的层序遍历过程中,我们是可以把⼀层的结点放在⼀个数组中去的。
    既然我们有这个数组,在合适的层数逆序就可以得到锯⻮形层序遍历的结果。
  4. C++代码
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<vector<int>> zigzagLevelOrder(TreeNode* root) {vector<vector<int>> vv;vector<int> v;if(root==nullptr)return vv;int cnt=0;queue<TreeNode*> q;q.push(root);while(!q.empty()){cnt++;int sz=q.size();while(sz--){TreeNode* tmp=q.front();q.pop();v.push_back(tmp->val);if(tmp->left!=nullptr)q.push(tmp->left);if(tmp->right!=nullptr)q.push(tmp->right);}if(cnt%2==0)reverse(v.begin(),v.end());vv.push_back(v);v.clear();}return vv;}
};

1.3 ⼆叉树最⼤宽度

  1. 题⽬链接:662. ⼆叉树最⼤宽度
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(层序遍历):
    算法思路:
  • 第⼀种思路(会超过内存限制):
    既然统计每⼀层的最⼤宽度,我们优先想到的就是利⽤层序遍历,把当前层的结点全部存在队列⾥⾯,利⽤队列的⻓度来计算每⼀层的宽度,统计出最⼤的宽度。但是,由于空节点也是需要计算在内的。因此,我们可以选择将空节点也存在队列⾥⾯。
    这个思路是我们正常会想到的思路,但是极端境况下,最左边⼀条⻓链,最右边⼀条⻓链,我们需要存⼏亿个空节点,会超过最⼤内存限制。
  • 第⼆种思路(利⽤⼆叉树的顺序存储 - 通过根节点的下标,计算左右孩⼦的下标):
    依旧是利⽤层序遍历,但是这⼀次队列⾥⾯不单单存结点信息,并且还存储当前结点如果在数组中存储所对应的下标(在我们学习数据结构 - 堆的时候,计算左右孩⼦的⽅式)。这样我们计算每⼀层宽度的时候,⽆需考虑空节点,只需将当层结点的左右结点的下标相减再加 1 即可。
    但是,这⾥有个细节问题:如果⼆叉树的层数⾮常恐怖的话,我们任何⼀种数据类型都不能存下下标的值。但是没有问题,因为
    • 我们数据的存储是⼀个环形的结构;
    • 并且题⽬说明,数据的范围在 int 这个类型的最⼤值的范围之内,因此不会超出⼀圈;
    • 因此,如果是求差值的话,我们⽆需考虑溢出的情况。
  1. C++代码
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:int widthOfBinaryTree(TreeNode* root) {queue<pair<TreeNode*,unsigned int>> q;q.push(make_pair(root,1));unsigned int cnt=0;while(!q.empty()){int sz=q.size();cnt=max(q.back().second-q.front().second+1,cnt);while(sz--){TreeNode* tmp=q.front().first;unsigned int ret=q.front().second;q.pop();if(tmp->left!=nullptr){q.push(make_pair(tmp->left,2*ret));}if(tmp->right!=nullptr){q.push(make_pair(tmp->right,2*ret+1));}}}return cnt;}
};
--------------------------------------------------------------------------------------------
//用数组模拟队列
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:int widthOfBinaryTree(TreeNode* root) {vector<pair<TreeNode*,unsigned int>> v;v.push_back({root,1});unsigned int cnt=0;while(v.size()){auto&[x1,y1]=v[0];auto&[x2,y2]=v.back();cnt=max(cnt,y2-y1+1);vector<pair<TreeNode*,unsigned int>> tmp;for(auto&[x,y]:v){if(x->left)tmp.push_back({x->left,2*y});if(x->right)tmp.push_back({x->right,2*y+1});}v=tmp;}return cnt;}
};

1.4 在每个树⾏中找最⼤值

  1. 题⽬链接:515. 在每个树⾏中找最⼤值
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(bfs):
    算法思路:
    层序遍历过程中,在执⾏让下⼀层节点⼊队的时候,我们是可以在循环中统计出当前层结点的最⼤值的。
    因此,可以在 bfs 的过程中,统计出每⼀层结点的最⼤值。
  4. C++代码
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<int> largestValues(TreeNode* root) {vector<int> v;if(root==nullptr)return v;queue<TreeNode*> q;q.push(root);int maxnum=INT_MIN;while(!q.empty()){int sz=q.size();while(sz--){TreeNode* tmp=q.front();maxnum=max(maxnum,tmp->val);q.pop();if(tmp->left)q.push(tmp->left);if(tmp->right)q.push(tmp->right);}v.push_back(maxnum);maxnum=INT_MIN;}return v;}
};

二、优先级队列(堆)示例:

2.1 最后⼀块⽯头的重量

  1. 题⽬链接:1046. 最后⼀块⽯头的重量
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(利⽤堆):
    算法思路:
    其实就是⼀个模拟的过程:
    • 每次从⽯堆中拿出最⼤的元素以及次⼤的元素,然后将它们粉碎;
    • 如果还有剩余,就将剩余的⽯头继续放在原始的⽯堆⾥⾯
    重复上⾯的操作,直到⽯堆⾥⾯只剩下⼀个元素,或者没有元素(因为所有的⽯头可能全部抵消了)
    那么主要的问题就是解决:
    • 如何顺利的拿出最⼤的⽯头以及次⼤的⽯头;
    • 并且将粉碎后的⽯头放⼊⽯堆中之后,也能快速找到下⼀轮粉碎的最⼤⽯头和次⼤⽯头;
    这不正好可以利⽤堆的特性来实现嘛?
    • 我们可以创建⼀个⼤根堆;
    • 然后将所有的⽯头放⼊⼤根堆中;
    • 每次拿出前两个堆顶元素粉碎⼀下,如果还有剩余,就将剩余的⽯头继续放⼊堆中;
    这样就能快速的模拟出这个过程。
  4. C++代码
class Solution {
public:struct cmp{bool operator()(int t1,int t2){return t1<t2;}};int lastStoneWeight(vector<int>& stones) {//priority_queue<int,vector<int>,less<int>> pq;priority_queue<int,vector<int>,cmp> pq;for(auto&e:stones)pq.push(e);while(pq.size()>1){int tmp1=pq.top();pq.pop();int tmp2=pq.top();pq.pop();int tmp=abs(tmp1-tmp2);if(tmp==0&&!pq.empty())continue;pq.push(tmp);}return pq.top();}
};

2.2 数据流中的第 K ⼤元素

  1. 题⽬链接:703. 数据流中的第 K ⼤元素

  2. 题⽬描述:
    在这里插入图片描述

  3. 解法(优先级队列):
    算法思路:
    我相信,看到 TopK 问题的时候,兄弟们应该能⽴⻢想到「堆」,这应该是刻在⻣⼦⾥的记忆。

  4. C++代码

class KthLargest {priority_queue<int,vector<int>,greater<int>> pq;int _k;
public:KthLargest(int k, vector<int>& nums) {_k=k;for(auto&e:nums){pq.push(e);if(pq.size()>_k)pq.pop();}}int add(int val) {pq.push(val);if(pq.size()>_k)pq.pop();return pq.top();}
};/*** Your KthLargest object will be instantiated and called as such:* KthLargest* obj = new KthLargest(k, nums);* int param_1 = obj->add(val);*/

2.3 前 K 个⾼频单词

  1. 题⽬链接:692. 前 K 个⾼频单词
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(堆):
    算法思路:
    • 稍微处理⼀下原数组:
    a. 我们需要知道每⼀个单词出现的频次,因此可以先使⽤哈希表,统计出每⼀个单词出现的频次;
    b. 然后在哈希表中,选出前 k ⼤的单词(为什么不在原数组中选呢?因为原数组中存在重复的单词,哈希表⾥⾯没有重复单词,并且还有每⼀个单词出现的频次)
    • 如何使⽤堆,拿出前 k ⼤元素:
    a. 先定义⼀个⾃定义排序,我们需要的是前 k ⼤,因此需要⼀个⼩根堆。但是当两个字符串的频次相同的时候,我们需要的是字典序较⼩的,此时是⼀个⼤根堆的属性,在定义⽐较器的时候需要注意!
    ▪ 当两个字符串出现的频次不同的时候:需要的是基于频次⽐较的⼩根堆
    ▪ 当两个字符串出现的频次相同的时候:需要的是基于字典序⽐较的⼤根堆
    b. 定义好⽐较器之后,依次将哈希表中的字符串插⼊到堆中,维持堆中的元素不超过 k 个;
    c. 遍历完整个哈希表后,堆中的剩余元素就是前 k ⼤的元素
  4. C++代码
class Solution {typedef pair<string,int> PII;
public:struct cmp{bool operator()(const PII& p1,const PII& p2){if(p1.second==p2.second)return p1.first<p2.first;// 频次相同,字典序按照⼤根堆的⽅式排列return p1.second>p2.second;}};vector<string> topKFrequent(vector<string>& words, int k) {priority_queue<PII,vector<PII>,cmp> pq;vector<string> v(k);unordered_map<string,int> hash;for(auto&e:words)hash[e]++;for(auto&e:hash){pq.push(e);if(pq.size()>k)pq.pop();}for(int i=k-1;i>=0;i--){v[i]=pq.top().first;pq.pop();}return v;}
};

2.4 数据流的中位数

  1. 题⽬链接:295. 数据流的中位数
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(利⽤两个堆):
    算法思路:
    这是⼀道关于「堆」这种数据结构的⼀个「经典应⽤」。
    我们可以将整个数组「按照⼤⼩」平分成两部分(如果不能平分,那就让较⼩部分的元素多⼀个),较⼩的部分称为左侧部分,较⼤的部分称为右侧部分:
    • 将左侧部分放⼊「⼤根堆」中,然后将右侧元素放⼊「⼩根堆」中;
    • 这样就能在 O(1) 的时间内拿到中间的⼀个数或者两个数,进⽽求的平均数。
    如下图所⽰:
    在这里插入图片描述

于是问题就变成了「如何将⼀个⼀个从数据流中过来的数据,动态调整到⼤根堆或者⼩根堆中,并且保证两个堆的元素⼀致,或者左侧堆的元素⽐右侧堆的元素多⼀个」为了⽅便叙述,将左侧的「⼤根堆」记为 left ,右侧的「⼩根堆」记为 right ,数据流中来的「数据」记为 x 。
其实,就是⼀个「分类讨论」的过程:

  • 如果左右堆的「数量相同」, left.size() == right.size() :
    a. 如果两个堆都是空的,直接将数据 x 放⼊到 left 中;
    b. 如果两个堆⾮空:
    i. 如果元素要放⼊左侧,也就是 x <= left.top() :那就直接放,因为不会影响我们制定的规则;
    ii. 如果要放⼊右侧
    • 可以先将 x 放⼊ right 中,
    • 然后把 right 的堆顶元素放⼊ left 中 ;
  • 如果左右堆的数量「不相同」,那就是 left.size() > right.size() :
    a. 这个时候我们关⼼的是 x 是否会放⼊ left 中,导致 left 变得过多:
    i. 如果 x 放⼊ right 中,也就是 x >= right.top() ,直接放;
    ii. 反之,就是需要放⼊ left 中:
    • 可以先将 x 放⼊ left 中,
    • 然后把 left 的堆顶元素放⼊ right 中 ;
    只要每⼀个新来的元素按照「上述规则」执⾏,就能保证 left 中放着整个数组排序后的「左半部分」, right 中放着整个数组排序后的「右半部分」,就能在 O(1) 的时间内求出平均数。
  1. C++代码
class MedianFinder 
{priority_queue<int,vector<int>,less<int>> left;//大根堆priority_queue<int,vector<int>,greater<int>> right;//小根堆
public:MedianFinder() {}void addNum(int num) {int n=left.size(),m=right.size();if(n==m){if(!left.empty()&&num>left.top()){right.push(num);left.push(right.top());right.pop();}else left.push(num);}else if(n>m){if(num<=left.top()){right.push(left.top());left.pop();left.push(num);}else right.push(num);}}double findMedian() {if(left.size()==right.size())return (left.top()+right.top())/2.0;else return left.top();}
};/*** Your MedianFinder object will be instantiated and called as such:* MedianFinder* obj = new MedianFinder();* obj->addNum(num);* double param_2 = obj->findMedian();*/

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

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

相关文章

数造科技入选中国信通院《高质量数字化转型产品及服务全景图》三大板块

9月24日&#xff0c;2024大模型数字生态发展大会暨“铸基计划”年中会议在北京召开。会上&#xff0c;中国信通院发布了2024年《高质量数字化转型产品及服务全景图&#xff08;上半年度&#xff09;》和《高质量数字化转型技术解决方案&#xff08;上半年度&#xff09;》等多项…

网络编程篇:UDP协议

一 UDP协议格式 16位源端口号&#xff1a;表示数据从哪里来。16位目的端口号&#xff1a;表示数据要到哪里去。16位UDP长度&#xff1a;表示整个数据报&#xff08;UDP首部UDP数据&#xff09;的长度。16位UDP检验和&#xff1a;如果UDP报文的检验和出错&#xff0c;就会直接将…

【Kubernetes】常见面试题汇总(五十三)

目录 118. pod 状态为 ErrlmagePull &#xff1f; 119.探测存活 pod 状态为 CrashLoopBackOff &#xff1f; 特别说明&#xff1a; 题目 1-68 属于【Kubernetes】的常规概念题&#xff0c;即 “ 汇总&#xff08;一&#xff09;~&#xff08;二十二&#xff09;” 。…

MongoDB聚合操作及索引底层原理

目录 链接:https://note.youdao.com/ynoteshare/index.html?id=50fdb657a9b06950fa255a82555b44a6&type=note&_time=1727951783296 本节课的内容: 聚合操作: 聚合管道操作: ​编辑 $match 进行文档筛选 ​编辑 将筛选和投影结合使用: ​编辑 多条件匹配: …

Springboot + netty + rabbitmq + myBatis

目录 0.为什么用消息队列1.代码文件创建结构2.pom.xml文件3.三个配置文件开发和生产环境4.Rabbitmq 基础配置类 TtlQueueConfig5.建立netty服务器 rabbitmq消息生产者6.建立常规队列的消费者 Consumer7.建立死信队列的消费者 DeadLetterConsumer8.建立mapper.xml文件9.建立map…

King3399 SDK(ubuntu文件系统)编译简明教程

该文章仅供参考&#xff0c;编写人不对任务实验设备、人员及测量结果负责&#xff01;&#xff01;&#xff01; 0 引言 文章主要介绍King3399&#xff08;瑞芯微rk3399开发板&#xff0c;荣品&#xff09;官方SDK&#xff08;Ubuntu文件系统&#xff09;编译过程&#xff0c…

【本地免费】SimpleTex 图像识别latex公式

文章目录 相关教程相关文献安装教程 由于mathpix开始收费了&#xff0c;于是本文将介绍一款目前本地免费的SimpleTex工具 相关教程 【超详细安装教程】LaTeX-OCR 图像识别latex公式&#xff08;开源免费&#xff09;_latex图片识别-CSDN博客 相关文献 SimpleTex主页——致力…

Elasticsearch使用Easy-Es + RestHighLevelClient实现深度分页跳页

注意&#xff01;&#xff01;&#xff01;博主只在测试环境试了一下&#xff0c;没有发到生产环境跑。因为代码还没写完客户说不用弄了( •̩̩̩̩&#xff3f;•̩̩̩̩ ) 也好&#xff0c;少个功能少点BUG 使用from size的时候发现存在max_result_window10000的限制&…

薄膜凸起和开裂是同一种应力导致的吗?

知识星球里的学员问&#xff1a;我们产线上薄膜出了质量问题&#xff0c;都一概归结为应力过大。麻烦讲讲应力的种类&#xff0c;以及不同种类的应力会造成哪些薄膜问题&#xff1f; 内应力的种类&#xff1f; 内应力的分类很多&#xff0c;如果我们按作用的效果来分&#xff…

树莓派 AI 摄像头(Raspberry Pi AI Camera)教程

系列文章目录 前言 人们使用 Raspberry Pi 产品构建人工智能项目的时间几乎与我们生产 Raspberry Pi 的时间一样长。随着我们发布功能越来越强大的设备&#xff0c;我们能够支持的原生应用范围也在不断扩大&#xff1b;但无论哪一代产品&#xff0c;总会有一些工作负载需要外部…

嵌入式外设应用(代码)

文章目录 1. 工业自动化2. 智能家居设备3. 汽车电子4. 生命体征监测仪5. 物联网应用 嵌入式外设应用广泛&#xff0c;有很多应用领域&#xff1a; 1. 工业自动化 应用场景&#xff1a;使用传感器监测设备状态&#xff0c;控制电机的启动和停止。 示例代码&#xff1a; #inc…

Stream流的终结方法(二)——collect

1.Stream流的终结方法 2. collect方法 collect方法用于收集流中的数据放到集合中去&#xff0c;可以将流中的数据放到List&#xff0c;Set&#xff0c;Map集合中 2.1 将流中的数据收集到List集合中 package com.njau.d10_my_stream;import java.util.*; import java.util.f…

SSL VPN | Easyconnect下载安装使用 (详尽)

EasyConnect是一款远程连接工具&#xff0c;为用户提供简便、快捷的远程访问和控制解决方案。 目录 下载 安装 使用 卸载 下载 通过链接进入官网技术支持板块 深信服技术支持-简单、高效、自助化服务 (sangfor.com.cn)https://support.sangfor.com.cn/ 选择软件下载 在安…

ElasticSearch学习笔记(三)Ubuntu 2204 server elasticsearch集群配置

如果你只是学习elasticsearch的增、删、改、查等相关操作&#xff0c;那么在windows上安装一个ES就可以了。但是你如果想在你的生产环境中使用Elasticsearch提供的强大的功能&#xff0c;那么还是建议你使用Linux操作系统。 本文以在Ubuntu 2204 server中安装elasticsearch 8.…

Redis:hash类型

Redis&#xff1a;hash类型 hash命令设置与读取HSETHGETHMGET 哈希操作HEXISTSHDELHKEYSHVALSHGETALLHLENHSETNXHINCRBYHINCRBYFLOAT 内部编码ziplisthashtable 目前主流的编程语言中&#xff0c;几乎都提供了哈希表相关的容器&#xff0c;Redis自然也会支持对应的内容&#xf…

【Godot4.3】用2D网格模拟一点透视

概述 空间的透视是可以在二维平面上参数化计算和模拟的。本篇基于CanvasItem绘制函数draw_colored_polygon()自带的UV坐标和贴图功能&#xff0c;实现基础的平行透视效果。 或者可以叫做一点透视&#xff0c;由一个消失点决定物体的透视效果。 测试代码 extends Node2Dvar re…

【课程学习】Wireless Communications

Goldsmith A. Wireless communications[M]. Cambridge university press, 2005. Wireless Communications 无线通信课程 文章目录 2-Path Loss, Shadowing, and Multipath2.4-Two-Ray Multipath Model时延扩展 delay spread P33 3-Statistical Multipath Channel Models3.3-Wid…

HarmonyOS应用六之应用程序进阶一

目录&#xff1a; 1、UIAbility的冷启动和UIAbility热启动2、静态资源和动态资源的访问3、页面跳转3.1、页面返回跳转 4、HAR的ArkUI组件、接口、资源&#xff0c;供其他应用或当前应用的其他模块引用4.1、导出HAR的ArkUI组件4.2、引用HAR的ArkUI组件 5、循环渲染6、状态管理最…

【MySQL】多表联合查询常见练习题

数据库表如下&#xff1a; teacher&#xff1a;老师表 course&#xff1a;课程表 student&#xff1a;学生表 class&#xff1a;班级表 sc&#xff1a;成绩表 一、根据上面5张表写sql语句 1. 查询” 01 “课程比” 02 “课程成绩高的学生的信息及课程分数 select student.…

在Ubuntu 20.04中安装CARLA

0. 引言 CARLA (Car Learning to Act) 是一款开源自动驾驶模拟器&#xff0c;其支持自动驾驶系统全管线的开发、训练和验证&#xff08;Development, Training, and Validation of autonomous driving systems&#xff09;。Carla提供了丰富的数字资产&#xff0c;例如城市布局…