LeetCode 1943. 描述绘画结果 (差分前缀和或者扫描线思想)

LeetCode 1943. 描述绘画结果 (差分前缀和或者扫描线思想)

题目描述

给你一个细长的画,用数轴表示。这幅画由若干有重叠的线段表示,每个线段有 独一无二 的颜色。给你二维整数数组 segments,其中 segments[i] = [start_i, end_i, color_i] 表示线段为 半开区间 [start_i, end_i) 且颜色为 color_i。

线段间重叠部分的颜色会被 混合。如果有两种或者更多颜色混合时,它们会形成一种新的颜色,用一个 集合 表示这个混合颜色。

比方说,如果颜色 2,4 和 6 被混合,那么结果颜色为 {2,4,6}。
为了简化题目,你不需要输出整个集合,只需要用集合中所有元素的 和 来表示颜色集合。

你想要用 最少数目 不重叠 半开区间 来 表示 这幅混合颜色的画。这些线段可以用二维数组 painting 表示,其中 painting[j] = [left_j, right_j, mix_j] 表示一个 半开区间 [left_j, right_j) 的颜色 和 为 mix_j。

比方说,这幅画由 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。

样例

输入: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),分别来自第二和第三个线段。

输入: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 ,来自第三个线段。

输入: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 * 10^4
segments[i].length == 3
1 <= start_i < end_i <= 10^5
1 <= colori <= 10^9
每种颜色 color_i 互不相同。

算法

方法一

(扫描线思想排序) O(nlogn)

  1. 每条线拆为左右端点 ——>{左端点l/右端点r,左端点标志1/右端点标志-1,值c},然后将所有端点从小到大排序,然后按顺序遍历。

  2. 初始化区间总和sum = 0,遍历一下,如果遇到左端点,sum+=c,否则sum-=c。

  3. 如何判断出现新线段:当前点和上个点的位置不同,且区间总和sum大于 0。

时间复杂度
主要是排序的时间复杂度为 O(nlogn)。
空间复杂度
需要 O(n) 的额外空间记录所有的端点。

方法二:

前缀和差分思想:

a[l] += c, a[r] -= c

->a[0] +...+a[l] = c, a[0] +...+a[r] = 0

这样前缀和就可以记录区间和的思想

看代码理解一下

class Solution {
public:
    vector<vector<long long>> splitPainting(vector<vector<int>>& segments) {
        vector<vector<int>> v;
        for(vector<int> x : segments){
            v.push_back({x[0], 1, x[2]});
            v.push_back({x[1], -1, x[2]});
        }
        sort(v.begin(), v.end());
        vector<vector<long long>> res;
        long long sum = v[0][2];
        for(int i = 1; i < v.size(); i++){
            if(v[i][0] != v[i - 1][0] && sum > 0){
                res.push_back({v[i - 1][0], v[i][0],sum});
            }
            sum += v[i][1] * v[i][2];
        }

        return res;
    }
};
class Solution {
public:
    vector<vector<long long>> splitPainting(vector<vector<int>>& segments) {
        // 计算每个位置对应的颜色和改变量并用哈希表存储
        unordered_map<int, long long> color;
        for (auto&& segment : segments){
            int l = segment[0];
            int r = segment[1];
            int c = segment[2];
            color[l] += c;
            color[r] -= c;
        }
        // 将哈希表转化为数组并按数轴坐标升序排序
        vector<pair<int, long long>> axis;
        for (auto&& [k, v] : color){
            axis.emplace_back(k, v);
        }
        sort(axis.begin(), axis.end());
        // 对数组求前缀和计算对应颜色和
        int n = axis.size();
        for (int i = 1; i < n; ++i){
            axis[i].second += axis[i-1].second;
        }
        // 遍历数组生成最终绘画结果
        vector<vector<long long>> res;
        for (int i = 0; i < n - 1; ++i){
            if (axis[i].second){
                res.emplace_back(vector<long long> {axis[i].first, axis[i+1].first, axis[i].second});
            }
        }
        return res;
    }
};
posted @ 2021-09-23 13:43  pxlsdz  阅读(541)  评论(0编辑  收藏  举报