You are given a list of segments, where each segment is represented as an array [start, end, color]
. Each segment paints the interval from start
(inclusive) to end
(exclusive) with the given color
. If multiple segments overlap, the colors are combined (summed) for the overlapping parts.
Your task is to describe the final painting as a list of non-overlapping intervals, where each interval is represented as [start, end, totalColor]
. Here, totalColor
is the sum of all colors covering that interval. The intervals should be sorted in increasing order of start
and should not overlap.
Constraints:
[start, end, color]
with start < end
At first glance, the problem looks like a classic interval merging or "sweep line" problem. The brute-force approach would be to create an array for every possible point, sum the colors at each position, and then combine contiguous parts with the same color sum. However, this would be slow and memory-intensive for large ranges.
Instead, we realize that the only points where the total color changes are the segment endpoints. So, we can focus on changes at these points, using a sweep line approach: as we process left-to-right, we add or remove colors at each endpoint, and whenever the total color changes, we record a new interval.
This optimization reduces both time and space, since we only process at most twice as many events as there are segments.
[start, end, color]
, record two events:start
, add color
to the totalend
, subtract color
from the totalcurr_color = 0
and prev_pos = None
curr_color > 0
and prev_pos != pos
, record interval [prev_pos, pos, curr_color]
curr_color
by adding/subtracting the event's colorprev_pos
to current pos
This approach is efficient because it only processes the points where changes actually occur, and uses a simple running total to track the color sum.
Suppose the input is segments = [[1,4,5], [4,7,7], [1,7,9]]
.
[[1,4,14], [4,7,16]]
The key insight is that the only interesting points are where the color sum changes: segment starts and ends. By turning the problem into a sweep line algorithm, we efficiently compute the result in O(n log n) time and O(n) space, without unnecessary brute-force enumeration. This method is both elegant and practical for interval summing and merging problems.
class Solution:
def splitPainting(self, segments):
from collections import defaultdict
events = defaultdict(int)
for start, end, color in segments:
events[start] += color
events[end] -= color
res = []
curr_color = 0
prev = None
for pos in sorted(events):
if prev is not None and curr_color != 0:
res.append([prev, pos, curr_color])
curr_color += events[pos]
prev = pos
return res
class Solution {
public:
vector<vector<long long>> splitPainting(vector<vector<int>>& segments) {
map<long long, long long> events;
for (auto& seg : segments) {
events[seg[0]] += seg[2];
events[seg[1]] -= seg[2];
}
vector<vector<long long>> res;
long long curr = 0, prev = -1;
for (auto& [pos, val] : events) {
if (prev != -1 && curr != 0) {
res.push_back({prev, pos, curr});
}
curr += val;
prev = pos;
}
return res;
}
};
class Solution {
public List<List<Long>> splitPainting(int[][] segments) {
TreeMap<Long, Long> events = new TreeMap<>();
for (int[] seg : segments) {
events.put((long)seg[0], events.getOrDefault((long)seg[0], 0L) + seg[2]);
events.put((long)seg[1], events.getOrDefault((long)seg[1], 0L) - seg[2]);
}
List<List<Long>> res = new ArrayList<>();
long curr = 0, prev = -1;
for (long pos : events.keySet()) {
if (prev != -1 && curr != 0) {
res.add(Arrays.asList(prev, pos, curr));
}
curr += events.get(pos);
prev = pos;
}
return res;
}
}
var splitPainting = function(segments) {
const events = new Map();
for (const [start, end, color] of segments) {
events.set(start, (events.get(start) || 0) + color);
events.set(end, (events.get(end) || 0) - color);
}
const keys = Array.from(events.keys()).sort((a, b) => a - b);
const res = [];
let prev = null, curr = 0;
for (const pos of keys) {
if (prev !== null && curr !== 0) {
res.push([prev, pos, curr]);
}
curr += events.get(pos);
prev = pos;
}
return res;
};