【map】【滑动窗口】【优先队列】LeetCode480滑动窗口中位数

news2025/1/18 11:52:20

作者推荐

动态规划 多源路径 字典树 LeetCode2977:转换字符串的最小成本

本题涉及知识点

滑动窗口 map 优先队列

题目

中位数是有序序列最中间的那个数。如果序列的长度是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。
例如:
[2,3,4],中位数是 3
[2,3],中位数是 (2 + 3) / 2 = 2.5
给你一个数组 nums,有一个长度为 k 的窗口从最左端滑动到最右端。窗口中有 k 个数,每次窗口向右移动 1 位。你的任务是找出每次窗口移动后得到的新窗口中元素的中位数,并输出由它们组成的数组。
示例:
给出 nums = [1,3,-1,-3,5,3,6,7],以及 k = 3。
窗口位置 中位数


[1 3 -1] -3 5 3 6 7 1
1 [3 -1 -3] 5 3 6 7 -1
1 3 [-1 -3 5] 3 6 7 -1
1 3 -1 [-3 5 3] 6 7 3
1 3 -1 -3 [5 3 6] 7 5
1 3 -1 -3 5 [3 6 7] 6
因此,返回该滑动窗口的中位数数组 [1,-1,-1,3,5,6]。
参数
你可以假设 k 始终有效,即:k 始终小于等于输入的非空数组的元素个数。
与真实值误差在 10 ^ -5 以内的答案将被视作正确答案。

map

map可以分成有序(单调)map和无序(哈希)map。还可分成单键map和多键map(允许重复的键)。本题用两个有序多键map。
令数据数量为n,无论n是奇数还是偶数,第二个map存放较大的n/2个数,第一个map存放余下的数。增加的时候,增加到任意一个map中,删除时那个map存在此数,就从那个map中删除。注意:如果两个map都有,则从任意一个map中删除。
需要确保两个map数量正确。如果第二个map的元素数量大于n/2,则将第二个map的数据移到第一个map;如果第二个map元素的数量小于n/2,则将第一个map的数据移动第二个map。
需要确保两个map有序 ,第一个map的元素小于等于第二个map的元素,即第一个map的最大值(*rbegin) 小于等于第二个map的最小值。如何删除rbegin ? std::prev(m_setMin.end()) 如果需要交换,说明max1 > min2 => max1不是第二个map的最小值,min2不是第一个map的最大值,所以可以先增加,再删除。

核心代码

class CMulMapMedian
{
public:
	void Add(int iNum)
	{
		m_setMax.insert(iNum);
		MakeValidSize();
		MakeSort();
	}
	void Del(int iNum)
	{
		if (m_setMax.count(iNum))
		{
			m_setMax.erase(m_setMax.find(iNum));
		}
		else
		{
			m_setMin.erase(m_setMin.find(iNum));
		}
		MakeValidSize();
		MakeSort();
	}
	double GetMedian()
	{
		if (m_setMin.size() == m_setMax.size())
		{
			return (*m_setMin.rbegin() + *m_setMax.begin()) / 2.0;
		}
		return *m_setMin.rbegin();
	}
protected:
	void MakeValidSize()
	{
		int iMaxSize = (m_setMin.size() + m_setMax.size()) / 2;
		while (m_setMax.size() < iMaxSize)
		{
			m_setMax.insert(*m_setMin.rbegin());
			m_setMin.erase(std::prev(m_setMin.end()));
		}
		while (m_setMax.size() > iMaxSize)
		{
			m_setMin.insert(*m_setMax.begin());
			m_setMax.erase(m_setMax.begin());
		}
	}
	void MakeSort()
	{
		if (m_setMax.empty())
		{
			return;
		}
		while (*m_setMin.rbegin() > *m_setMax.begin())
		{
			m_setMin.insert(*m_setMax.begin());
			m_setMax.insert(*m_setMin.rbegin());
			m_setMin.erase(std::prev(m_setMin.end()));
			m_setMax.erase(m_setMax.begin());			
		}
	}

	std::multiset<double> m_setMin, m_setMax;
};
class Solution {
public:
	vector<double> medianSlidingWindow(vector<int>& nums, int k) {
		CMulMapMedian median;
		int i = 0;
		for (; i < k; i++)
		{
			median.Add(nums[i]);
		}
		vector<double> vRet;
		vRet.push_back(median.GetMedian());
		for (; i < nums.size(); i++)
		{
			median.Add(nums[i]);
			median.Del(nums[i - k]);
			vRet.push_back(median.GetMedian());
		}
		return vRet;
	}
};

测试用例

int main()
{
	vector<int> nums;
	int k;
	{
		Solution sln;
		nums = { 1, 3, -1, -3, 5, 3, 6, 7 },k = 3;
		auto res = sln.medianSlidingWindow(nums, k);
		Assert(vector<double>{1, -1, -1, 3, 5, 6}, res);
	}
	

	
}

双优先队列(堆)+延长删除

优先队列无法删除指定元素,可以记录需要删除的元素,如果堆顶元素是需要删除的元素,则删除。

class CMedian
{
public:
	void AddNum(int iNum)
	{
		m_queTopMin.emplace(iNum);
		MakeNumValid();	
		MakeSmallBig();
	}
	void Remove(int iNum)
	{
		if (m_queTopMax.size() && (iNum <= m_queTopMax.top()))
		{
			m_setTopMaxDel.insert(iNum);
		}
		else
		{
			m_setTopMinDel.insert(iNum);
		}

		PopIsTopIsDel(m_queTopMin, m_setTopMinDel);
		PopIsTopIsDel(m_queTopMax, m_setTopMaxDel);
		MakeNumValid();
		MakeSmallBig();
	}
	double Median()
	{
		const int iMaxNum = m_queTopMin.size() - m_setTopMinDel.size();
		const int iMinNum = m_queTopMax.size() - m_setTopMaxDel.size();
		if (iMaxNum > iMinNum)
		{
			return m_queTopMin.top();
		}
		return ((double)m_queTopMin.top() + m_queTopMax.top())/2.0;
	}
	template<class T>
	void PopIsTopIsDel(T& que, std::unordered_multiset<int>& setTopMaxDel)
	{
		while (que.size() && (setTopMaxDel.count(que.top())))
		{
			setTopMaxDel.erase(setTopMaxDel.find(que.top()));
			que.pop();
		}
	}
	void MakeNumValid()
	{
		const int iMaxNum = m_queTopMin.size() - m_setTopMinDel.size();
		const int iMinNum = m_queTopMax.size() - m_setTopMaxDel.size();
		//确保两个队的数量
		if (iMaxNum > iMinNum + 1)
		{
			int tmp = m_queTopMin.top();
			m_queTopMin.pop();
			m_queTopMax.emplace(tmp);
			PopIsTopIsDel(m_queTopMin, m_setTopMinDel);
		}
		if (iMinNum > iMaxNum)
		{
			int tmp = m_queTopMax.top();
			m_queTopMax.pop();
			m_queTopMin.push(tmp);
			PopIsTopIsDel(m_queTopMax, m_setTopMaxDel);
		}
	}
	void MakeSmallBig()
	{
		if (m_queTopMin.empty() || m_queTopMax.empty())
		{
			return;
		}
		while (m_queTopMin.top() < m_queTopMax.top())
		{
			const int iOldTopMin = m_queTopMin.top();
			const int iOldTopMax = m_queTopMax.top();
			m_queTopMin.pop();
			m_queTopMax.pop();
			m_queTopMin.emplace(iOldTopMax);
			m_queTopMax.emplace(iOldTopMin);
			PopIsTopIsDel(m_queTopMin, m_setTopMinDel);
			PopIsTopIsDel(m_queTopMax, m_setTopMaxDel);
		}
	}
	std::priority_queue<int> m_queTopMax;
	std::priority_queue<int, vector<int>, greater<int>> m_queTopMin;
	std::unordered_multiset<int> m_setTopMaxDel, m_setTopMinDel;
};

class Solution {
public:
vector medianSlidingWindow(vector& nums, int k) {
int i = 0;
CMedian hlp;
for (; i + 1 < k; i++)
{
hlp.AddNum(nums[i]);
}
vector vRet;
for (; i < nums.size(); i++)
{
hlp.AddNum(nums[i]);
if (i - k >= 0)
{
hlp.Remove(nums[i - k]);
}
vRet.emplace_back(hlp.Median());
}
return vRet;
}
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法C++ 实现。

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

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

相关文章

springBoot整合redis做缓存

一、Redis介绍 Redis是当前比较热门的NOSQL系统之一&#xff0c;它是一个开源的使用ANSI c语言编写的key-value存储系统&#xff08;区别于MySQL的二维表格的形式存储。&#xff09;。和Memcache类似&#xff0c;但很大程度补偿了Memcache的不足。和Memcache一样&#xff0c;R…

yolov8 细胞分割数据集准备及训练

1、数据 下载:https://universe.roboflow.com/motherson-hm/5-part-diff 500来张,5个类别(嗜碱性细胞、嗜酸细胞、淋巴细胞、单核细胞、中性粒细胞) yolo 分割数据标注格式: 与检测类似,就是坐标分割有多个 2、训练 训练yaml: seg_data.yaml (与检测格式一样) …

sheng的学习笔记-卷积神经网络

源自吴恩达的深度学习课程&#xff0c;仅用于笔记&#xff0c;便于自行复习 导论 1&#xff09;什么是卷积神经网络 卷积神经网络&#xff0c;也就是convolutional neural networks &#xff08;简称CNN&#xff09;&#xff0c;使用卷积算法的神经网络&#xff0c;常用于计…

四川云汇优想教育咨询有限公司抖店开店靠谱吗

随着短视频平台的崛起&#xff0c;抖音已经成为了越来越多人展示自我、分享生活、推广产品的重要平台。因此&#xff0c;开设抖店已经成为了很多人的创业选择。如果您也有兴趣开设抖店&#xff0c;那么四川云汇优想教育咨询有限公司抖店开店服务将是您的不二之选。 四川云汇优想…

推荐五款简洁而实用的工具,值得你尝试

​ 分享快乐是生活中美好的瞬间&#xff0c;而分享简单巧妙的工具也能令我愉悦。这五款工具简洁而实用&#xff0c;值得你尝试。 1.视频播放器——Potplayer Potplayer是一款视频播放器&#xff0c;支持DXVA、CUDA和QuickSync等硬件加速技术&#xff0c;提供高效的视频播放性…

【数据结构和算法】---二叉树(2)--堆的实现和应用

目录 一、堆的概念及结构二、堆结构的实现2.1堆向下调整算法2.2堆向上调整算法2.3删除堆顶元素2.4插入元素2.5其他函数接口 三、堆结构的应用3.1堆排序3.2Top-k问题 四、堆概念及结构相关题目 一、堆的概念及结构 如果有一个数字集合&#xff0c;并把它的所有元素按完全二叉树…

2022 年全国职业院校技能大赛高职组云计算正式赛卷第二场-容器云

2022 年全国职业院校技能大赛高职组云计算赛项试卷 云计算赛项第二场-容器云 目录 2022 年全国职业院校技能大赛高职组云计算赛项试卷 【赛程名称】云计算赛项第二场-容器云 【任务 1】容器云平台搭建[5 分] 【任务 2】容器云应用部署&#xff1a; Docker Compose 编排部署[7.0…

文件操作安全之-目录穿越流量告警运营分析篇

本文从目录穿越的定义,目录穿越的多种编码流量数据包示例,目录穿越的suricata规则,目录穿越的告警分析研判,目录穿越的处置建议等几个方面阐述如何通过IDS/NDR,态势感知等流量平台的目录穿越类型的告警的线索,开展日常安全运营工作,从而挖掘有意义的安全事件。 目录穿越…

二分查找——OJ题(一)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、二分查找1、题目讲解2、算法原理3、代码实现 二、在排序数组中查找元素的第一个和最后一个…

Frappe Charts:数据可视化的强大工具

一、产品简介&#xff1a; 一个简单、零依赖、响应式的 开源SVG 图表库。这个图表库无论是数据更新还是屏幕大小变化&#xff0c;都能快速响应并更新图表。数据生成和悬停查看都有舒服的交互动效&#xff0c;体验感很好。不仅支持配置颜色&#xff0c;外观定制也很方便。还支持…

Python 常用模块Logging

Python 常用模块Logging 【序言】 logging模块是专门用来做日志记录的模块 【一】日志等级 默认打印结果到终端上 CRITICAL 50 # 致命错误 ERROR 40 # 错误 WARNING 30 # 警告 INFO 20 # 消息 DEBUG 10 # 调试 NOTSET 0 # 不设置示例&#xff1a; 默认级别为…

Vue3+ElementPlus: 给点击按钮添加触发提示

一、需求 在Vue3项目中&#xff0c;有一个下载按钮&#xff0c;当鼠标悬浮在按钮上面时&#xff0c;会出现文字提示用户可以点击按钮进行数据的下载技术栈 Vue3 ElementPlusTooltip组件 ElementPlus中的Tooltip组件 &#xff0c;可用于展示鼠标 hover 时的提示信息 二、实现…

jenkins解决工具找不到的问题

--------------------------插件选择版本最好能跟服务器对上

EDM打开率突然下降的原因:深入分析并采取应对措施

在跨境电商和出海领域&#xff0c;电子邮件营销&#xff08;Email Marketing&#xff09;已成为企业营销推广及与客户互动的主要手段之一&#xff0c;在企业营销中起到主导地位。但是&#xff0c;有时我们不得不面对EDM打开率突然下降的困境。那么&#xff0c;EDM打开率下降的原…

二叉树数据结构:深入了解二叉树的概念、特性与结构

在探索栈和队列之后&#xff08;大家可以移步至我的数据结构专栏&#xff09;&#xff1a;T-rLN的数据结构专栏 我们转向了更为复杂而有趣的数据结构——二叉树。本文将引领我们进入二叉树的世界&#xff0c;从最基本的概念和结构开始&#xff0c;逐步深入了解二叉树的顺序结构…

可用于blender制作3D动画的全身动捕设备

随着动捕设备的进步&#xff0c;在3D建模和动画制作领域中&#xff0c;动捕设备被广泛应用&#xff0c;以便创建更加真实和自然的角色动画。其中&#xff0c;blender作为一款开源的3D建模和动画软件&#xff0c;搭配全身动捕设备使用&#xff0c;更加激发了用户角色动画创作灵感…

【ARMv8M Cortex-M33 系列 2 -- Cortex-M33 JLink 连接 及 JFlash 烧写介绍】

文章目录 Jlink 工具JLink 命令行示例JFlash 烧写问题Jlink 工具 J-Link 是 SEGGER 提供的一款流行的 JTAG 调试器,它支持多个平台和处理器。JLink.exe 是 J-Link 调试器的命令行接口,它允许用户通过命令行执行一系列操作,例如编程、擦除、调试等。 工具链接: https://ww…

使用VMware创建CentOS7虚拟机详细教程

创建虚拟机 首先以管理员身份运行vmware17&#xff0c;进入后点击创建虚拟机。 直接点击下一步&#xff0c;开始自定义安装。 继续点击下一步 提前将iso文件准备好&#xff0c;这里用的是centos7&#xff0c;也可以使用其他系统的文件&#xff0c;然后点击下一步。 下来就是修…

IDEA、VSCode等快速连接Github(Mac版)

问题描述 在本地书写✍️完代码后, 想要git push到Github上面, 出现延迟错误; 导致经常push不上去, 如下图所示; 解决方案 进入电脑终端; 输入下列命令; sudo vim /etc/hosts输入密码; 按下 I 键, 进行编辑操作; 将下列语句复制到空白区, 然后按下esc按键, 然后输入:wq即可…

【计算机毕业设计】SSM医疗药品采购系统

项目介绍 ssm医疗药品采购系统。主要功能有&#xff1a; 用户管理&#xff1a;管理员列表&#xff1b; 采购管理&#xff1a;采购列表&#xff1b; 药品出库&#xff1a;药品出库&#xff1b; 库存管理&#xff1a;库存统计&#xff1b; 数据维护&#xff1a;药品列表、仓库…