【区间合并 差分 栈】3169. 无需开会的工作日

2024-06-15 05:52

本文主要是介绍【区间合并 差分 栈】3169. 无需开会的工作日,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文涉及知识点

区间合并
差分数组(大约2024年7月1号发)

LeetCode3169. 无需开会的工作日

给你一个正整数 days,表示员工可工作的总天数(从第 1 天开始)。另给你一个二维数组 meetings,长度为 n,其中 meetings[i] = [start_i, end_i] 表示第 i 次会议的开始和结束天数(包含首尾)。
返回员工可工作且没有安排会议的天数。
注意:会议时间可能会有重叠。

示例 1:
输入:days = 10, meetings = [[5,7],[1,3],[9,10]]
输出:2
解释:
第 4 天和第 8 天没有安排会议。
示例 2:
输入:days = 5, meetings = [[2,4],[1,3]]
输出:1
解释:
第 5 天没有安排会议。
示例 3:
输入:days = 6, meetings = [[1,6]]
输出:0
解释:
所有工作日都安排了会议。
提示:
1 <= days <= 109
1 <= meetings.length <= 105
meetings[i].length == 2
1 <= meetings[i][0] <= meetings[i][1] <= days

差分

days最大109,所以不能有差分数组,只能用差分map,求和的需要有序。
统计开会的时间,比不开会的时间简单。
mDiff[si]++ mDiff[ei+1]-- 表示[si,ei] 一场会议。
∀ \forall mDiff的键 key,其下一个键为nkey。
∀ \forall k ∈ \in [key,nkey) mDiff[k]都为0,省略。
即:
x = ∑ i : 0 k e y m D i f f [ i ] = ∑ i : 0 k m D i f f [ i ] x = \sum_{i:0}^{key}mDiff[i] \quad = \sum_{i:0}^{k}mDiff[i] x=i:0keymDiff[i]=i:0kmDiff[i]
如果x不为0,则[key,nkey)全部要开会。

核心代码

class Solution {
public:int countDays(int days, vector<vector<int>>& meetings) {map<int, int> mDiff;for (const auto& v : meetings) {mDiff[v[0]]++;mDiff[v[1] + 1]--;}int iRet = 0;int sum = 0;for (auto it = mDiff.begin(); std::next(it) != mDiff.end(); ++it) {auto itNext = std::next(it);sum += it->second;if (sum > 0) {iRet += itNext->first - it->first;}}return  days - iRet;}
};

单元测试

template<class T1,class T2>
void AssertEx(const T1& t1, const T2& t2)
{Assert::AreEqual(t1 , t2);
}template<class T>
void AssertEx(const vector<T>& v1, const vector<T>& v2)
{Assert::AreEqual(v1.size(), v2.size());	for (int i = 0; i < v1.size(); i++){Assert::AreEqual(v1[i], v2[i]);}
}template<class T>
void AssertV2(vector<vector<T>> vv1, vector<vector<T>> vv2)
{sort(vv1.begin(), vv1.end());sort(vv2.begin(), vv2.end());Assert::AreEqual(vv1.size(), vv2.size());for (int i = 0; i < vv1.size(); i++){AssertEx(vv1[i], vv2[i]);}
}namespace UnitTest
{int days;vector<vector<int>> meetings;TEST_CLASS(UnitTest){public:TEST_METHOD(TestMethod1){days = 5, meetings = { {2,4},{1,3} };auto res = Solution().countDays(days, meetings);AssertEx(1, res);}};
}

封装类

template<class KEY=int,class VALUE=int>
class CMapDiff
{
public:void Set(KEY left, KEY rExclue, VALUE value) {m_mDiff[left]+= value;m_mDiff[rExclue]-= value;}vector<pair<KEY, VALUE>> Ans()const {vector<pair<KEY, VALUE>> res;VALUE sum = 0;for (const auto& [key,value]: m_mDiff) {			sum += value;res.emplace_back(make_pair(key, sum));}return res;}
protected:map<KEY, VALUE> m_mDiff;
};
class Solution {
public:int countDays(int days, vector<vector<int>>& meetings) {CMapDiff mDiff;for (const auto& v : meetings) {mDiff.Set(v[0], v[1] + 1,1);}auto v = mDiff.Ans();int iRet = 0;for (int i = 0; i + 1 < v.size(); i++) {if( v[i].second > 0 ){ iRet += v[i + 1].first - v[i].first; }			}return  days - iRet;}
};

差分(旧版)

值相同的区间进行了合并,没多大意义。

class Solution {
public:int countDays(int days, vector<vector<int>>& meetings) {map<int, int> mDiff;for (const auto& v : meetings) {mDiff[v[0]]++;mDiff[v[1]+1]--;}vector<pair<int, int>> v;if (1 != mDiff.begin()->first) {v.emplace_back(make_pair(1, 0));}int sum = 0;for (const auto& [day, cnt] : mDiff) {sum += cnt;v.emplace_back(day, (sum>0));}		vector<pair<int, int>> v1;v1.emplace_back(v[0]);for (int i = 1; i < v.size(); i++) {if (v[i].second != v1.back().second) {v1.emplace_back(v[i]);}}if (v1.back().first <= days) {v1.emplace_back(make_pair(days + 1, 0));}int ret = 0;for (int i = 0; i + 1 < v1.size(); i++) {if (0 == v1[i].second) {ret += v1[i + 1].first - v1[i].first;}}return ret;}
};

区间合并

先按开始时间的升序排序。依次入栈,如果当前元素和栈顶元素能合并则合并:开始时间不变,终止时间取两者最大值;否则,直接入栈。

template<class ELE>
void MaxSelf(ELE* seft, const ELE& other)
{*seft = max(*seft, other);
}class Solution {
public:int countDays(int days, vector<vector<int>>& meetings) {sort(meetings.begin(), meetings.end(), [&](const auto& v1, const auto& v2) {return v1[0] < v2[0]; });stack<pair<int, int>> sta;for (const auto& v : meetings) {if (sta.empty() || (sta.top().second < v[0])) {sta.emplace(make_pair(v[0], v[1] + 1));}else {MaxSelf(&sta.top().second, v[1] + 1);}}int iRet = 0;while (sta.size()) {iRet += sta.top().second - sta.top().first;sta.pop();}return  days - iRet;}
};

封装后

class CIntervalMerging
{
public:CIntervalMerging( vector<vector<int>> vInterval,bool bIncludeEnd) {sort(vInterval.begin(), vInterval.end(), [&](const auto& v1, const auto& v2) {return v1[0] < v2[0]; });for (const auto& v : vInterval) {if (V.empty() || (V.back().second < v[0])) {V.emplace_back(make_pair(v[0], v[1] + bIncludeEnd));}else {V.back().second = max(V.back().second, v[1] + bIncludeEnd);}}}vector<pair<int, int>> V;
};
class Solution {
public:int countDays(int days, vector<vector<int>>& meetings) {	CIntervalMerging im(meetings, true);int iRet = std::accumulate(im.V.begin(), im.V.end(), 0, [](auto val, auto pr) {return val + pr.second - pr.first; });return  days - iRet;}
};

扩展阅读

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

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

相关推荐

我想对大家说的话
《喜缺全书算法册》以原理、正确性证明、总结为主。
按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

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

这篇关于【区间合并 差分 栈】3169. 无需开会的工作日的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1062599

相关文章

Python中合并列表(list)的六种方法小结

《Python中合并列表(list)的六种方法小结》本文主要介绍了Python中合并列表(list)的六种方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录一、直接用 + 合并列表二、用 extend() js方法三、用 zip() 函数交叉合并四、用

利用Python实现Excel文件智能合并工具

《利用Python实现Excel文件智能合并工具》有时候,我们需要将多个Excel文件按照特定顺序合并成一个文件,这样可以更方便地进行后续的数据处理和分析,下面我们看看如何使用Python实现Exce... 目录运行结果为什么需要这个工具技术实现工具的核心功能代码解析使用示例工具优化与扩展有时候,我们需要将

Python实现获取带合并单元格的表格数据

《Python实现获取带合并单元格的表格数据》由于在日常运维中经常出现一些合并单元格的表格,如果要获取数据比较麻烦,所以本文我们就来聊聊如何使用Python实现获取带合并单元格的表格数据吧... 由于在日常运维中经常出现一些合并单元格的表格,如果要获取数据比较麻烦,现将将封装成类,并通过调用list_exc

Python实现合并与拆分多个PDF文档中的指定页

《Python实现合并与拆分多个PDF文档中的指定页》这篇文章主要为大家详细介绍了如何使用Python实现将多个PDF文档中的指定页合并生成新的PDF以及拆分PDF,感兴趣的小伙伴可以参考一下... 安装所需要的库pip install PyPDF2 -i https://pypi.tuna.tsingh

无需邀请码!Manus复刻开源版OpenManus下载安装与体验

《无需邀请码!Manus复刻开源版OpenManus下载安装与体验》Manus的完美复刻开源版OpenManus安装与体验,无需邀请码,手把手教你如何在本地安装与配置Manus的开源版OpenManu... Manus是什么?Manus 是 Monica 团队推出的全球首款通用型 AI Agent。Man

使用Apache POI在Java中实现Excel单元格的合并

《使用ApachePOI在Java中实现Excel单元格的合并》在日常工作中,Excel是一个不可或缺的工具,尤其是在处理大量数据时,本文将介绍如何使用ApachePOI库在Java中实现Excel... 目录工具类介绍工具类代码调用示例依赖配置总结在日常工作中,Excel 是一个不可或缺的工http://

使用Python创建一个能够筛选文件的PDF合并工具

《使用Python创建一个能够筛选文件的PDF合并工具》这篇文章主要为大家详细介绍了如何使用Python创建一个能够筛选文件的PDF合并工具,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录背景主要功能全部代码代码解析1. 初始化 wx.Frame 窗口2. 创建工具栏3. 创建布局和界面控件4

Python自动化办公之合并多个Excel

《Python自动化办公之合并多个Excel》在日常的办公自动化工作中,尤其是处理大量数据时,合并多个Excel表格是一个常见且繁琐的任务,下面小编就来为大家介绍一下如何使用Python轻松实现合... 目录为什么选择 python 自动化目标使用 Python 合并多个 Excel 文件安装所需库示例代码

使用Python合并 Excel单元格指定行列或单元格范围

《使用Python合并Excel单元格指定行列或单元格范围》合并Excel单元格是Excel数据处理和表格设计中的一项常用操作,本文将介绍如何通过Python合并Excel中的指定行列或单... 目录python Excel库安装Python合并Excel 中的指定行Python合并Excel 中的指定列P

基于C#实现PDF文件合并工具

《基于C#实现PDF文件合并工具》这篇文章主要为大家详细介绍了如何基于C#实现一个简单的PDF文件合并工具,文中的示例代码简洁易懂,有需要的小伙伴可以跟随小编一起学习一下... 界面主要用于发票PDF文件的合并。经常出差要报销的很有用。代码using System;using System.Col