【C++差分数组】1943. 描述绘画结果|1969

本文涉及知识点

C++差分数组

LeetCode1943. 描述绘画结果

给你一个细长的画,用数轴表示。这幅画由若干有重叠的线段表示,每个线段有 独一无二 的颜色。给你二维整数数组 segments ,其中 segments[i] = [starti, endi, colori] 表示线段为 半开区间 [starti, endi) 且颜色为 colori 。
线段间重叠部分的颜色会被 混合 。如果有两种或者更多颜色混合时,它们会形成一种新的颜色,用一个 集合 表示这个混合颜色。
比方说,如果颜色 2 ,4 和 6 被混合,那么结果颜色为 {2,4,6} 。
为了简化题目,你不需要输出整个集合,只需要用集合中所有元素的 和 来表示颜色集合。
你想要用 最少数目 不重叠 半开区间 来 表示 这幅混合颜色的画。这些线段可以用二维数组 painting 表示,其中 painting[j] = [leftj, rightj, mixj] 表示一个 半开区间[leftj, rightj) 的颜色 和 为 mixj 。

比方说,这幅画由 segments = [[1,4,5],[1,7,7]] 组成,那么它可以表示为 painting = [[1,4,12],[4,7,7]] ,因为:
[1,4) 由颜色 {5,7} 组成(和为 12),分别来自第一个线段和第二个线段。
[4,7) 由颜色 {7} 组成,来自第二个线段。
请你返回二维数组 painting ,它表示最终绘画的结果(没有 被涂色的部分不出现在结果中)。你可以按 任意顺序 返回最终数组的结果。
半开区间 [a, b) 是数轴上点 a 和点 b 之间的部分,包含 点 a 且 不包含 点 b 。
示例 1:
在这里插入图片描述

输入:segments = [[1,4,5],[4,7,7],[1,7,9]]
输出:[[1,4,14],[4,7,16]]
解释:绘画结果可以表示为:

  • [1,4) 颜色为 {5,9} (和为 14),分别来自第一和第二个线段。
  • [4,7) 颜色为 {7,9} (和为 16),分别来自第二和第三个线段。
    示例 2:

在这里插入图片描述

输入:segments = [[1,7,9],[6,8,15],[8,10,7]]
输出:[[1,6,9],[6,7,24],[7,8,15],[8,10,7]]
解释:绘画结果可以以表示为:

  • [1,6) 颜色为 9 ,来自第一个线段。
  • [6,7) 颜色为 {9,15} (和为 24),来自第一和第二个线段。
  • [7,8) 颜色为 15 ,来自第二个线段。
  • [8,10) 颜色为 7 ,来自第三个线段。
    示例 3:
    在这里插入图片描述

输入:segments = [[1,4,5],[1,4,7],[4,7,1],[4,7,11]]
输出:[[1,4,12],[4,7,12]]
解释:绘画结果可以表示为:

  • [1,4) 颜色为 {5,7} (和为 12),分别来自第一和第二个线段。
  • [4,7) 颜色为 {1,11} (和为 12),分别来自第三和第四个线段。
    注意,只返回一个单独的线段 [1,7) 是不正确的,因为混合颜色的集合不相同。

提示:
1 <= segments.length <= 2 * 104
segments[i].length == 3
1 <= starti < endi <= 105
1 <= colori <= 109
每种颜色 colori 互不相同。

差分数组

diff[i]记录点i处颜色和的增量,对应的数据数组为a。难点在区间划分,colori互不相同是题眼。对于任意starti,endi。
starti一定是最终区间某一区间的开始,因为starti和starti-1的颜色一定不同。前者包括颜色colori,后者不包括。
同理,endi一定是某一区间的结束。
同理,若starti-1存在,且a[starti-1]不为0,则starti也是终点。
同理,若a[endi]不为0,则endi也是终点。
且新区间的开始和结束一定是以上四种情况。
rang[i]&1 表示i是区间起点,rang[i]&2 表示i是区间终点。

代码

核心代码

class Solution {
		public:
			vector<vector<long long>> splitPainting(vector<vector<int>>& segments) {
				const int N = 100'000;
				vector<long long> vDiff(N + 1);
				for (const auto& v : segments) {
					vDiff[v[0]] += v[2];
					vDiff[v[1] ]-= v[2];
				}

				long long cur = 0;
				vector<long long> a;
				for (int i = 0; i <= N; i++)
				{
					cur += vDiff[i];
					a.emplace_back(cur);
				}
				vector<int> rang(N+1);
				for (const auto& v : segments) {
					rang[v[0]] |= 1;
					rang[v[1]] |= 2;
					if ((v[0] > 0) && (a[v[0] - 1] > 0)) {
						rang[v[0]] |= 2;
					}
					if (a[v[1]] > 0) {
						rang[v[1]] |= 1;
					}
				}

				vector<vector<long long>> ret;
				for (int i = 0; i <= N; i++) {
					if (2 & rang[i]) {
						ret.back()[1] = i;
					}
					if (1 & rang[i]) {
						ret.emplace_back(vector<long long>{i, 0, a[i]});
					}
				}
				return ret;
			}
		};

单元测试

vector<vector<int>> segments;

		TEST_METHOD(TestMethod11)
		{
			segments = { {1,4,5},{4,7,7},{1,7,9} };
			auto res = Solution().splitPainting(segments);
			AssertV2(vector<vector<long long>>{ {1,4,14},{4,7,16} }, res);
		}
		TEST_METHOD(TestMethod12)
		{
			segments = { {1,7,9},{6,8,15},{8,10,7} };
			auto res = Solution().splitPainting(segments);
			AssertV2(vector<vector<long long>>{ {1, 6, 9}, { 6,7,24 }, { 7,8,15 }, { 8,10,7 }}, res);
		}
		TEST_METHOD(TestMethod13)
		{
			segments = { {1,4,5},{1,4,7},{4,7,1},{4,7,11} };
			auto res = Solution().splitPainting(segments);
			AssertV2(vector<vector<long long>>{ {1, 4, 12}, { 4,7,12 }}, res);
		}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步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++**实现。

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闻缺陷则喜何志丹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值