class Solution:
def isPrintable(self, targetGrid):
from collections import defaultdict, deque
n, m = len(targetGrid), len(targetGrid[0])
colors = set()
bounds = {}
for i in range(n):
for j in range(m):
c = targetGrid[i][j]
colors.add(c)
if c not in bounds:
bounds[c] = [i, i, j, j] # minRow, maxRow, minCol, maxCol
else:
bounds[c][0] = min(bounds[c][0], i)
bounds[c][1] = max(bounds[c][1], i)
bounds[c][2] = min(bounds[c][2], j)
bounds[c][3] = max(bounds[c][3], j)
# Build dependency graph
graph = defaultdict(set)
indegree = defaultdict(int)
for c in colors:
minR, maxR, minC, maxC = bounds[c]
for i in range(minR, maxR+1):
for j in range(minC, maxC+1):
if targetGrid[i][j] != c:
if targetGrid[i][j] not in graph[c]:
graph[c].add(targetGrid[i][j])
indegree[targetGrid[i][j]] += 1
# Topological sort
queue = deque([c for c in colors if indegree[c]==0])
removed = set()
while queue:
c = queue.popleft()
removed.add(c)
for nei in graph[c]:
indegree[nei] -= 1
if indegree[nei] == 0:
queue.append(nei)
return len(removed) == len(colors)
class Solution {
public:
bool isPrintable(vector<vector<int>>& targetGrid) {
int n = targetGrid.size(), m = targetGrid[0].size();
unordered_set<int> colors;
unordered_map<int, vector<int>> bounds; // minRow, maxRow, minCol, maxCol
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
int c = targetGrid[i][j];
colors.insert(c);
if (bounds.find(c) == bounds.end()) {
bounds[c] = {i, i, j, j};
} else {
bounds[c][0] = min(bounds[c][0], i);
bounds[c][1] = max(bounds[c][1], i);
bounds[c][2] = min(bounds[c][2], j);
bounds[c][3] = max(bounds[c][3], j);
}
}
}
unordered_map<int, unordered_set<int>> graph;
unordered_map<int, int> indegree;
for (auto c : colors) {
int minR = bounds[c][0], maxR = bounds[c][1], minC = bounds[c][2], maxC = bounds[c][3];
for (int i = minR; i <= maxR; ++i) {
for (int j = minC; j <= maxC; ++j) {
if (targetGrid[i][j] != c) {
if (graph[c].find(targetGrid[i][j]) == graph[c].end()) {
graph[c].insert(targetGrid[i][j]);
indegree[targetGrid[i][j]]++;
}
}
}
}
}
queue<int> q;
for (auto c : colors)
if (indegree[c] == 0) q.push(c);
unordered_set<int> removed;
while (!q.empty()) {
int c = q.front(); q.pop();
removed.insert(c);
for (int nei : graph[c]) {
indegree[nei]--;
if (indegree[nei] == 0) q.push(nei);
}
}
return removed.size() == colors.size();
}
};
class Solution {
public boolean isPrintable(int[][] targetGrid) {
int n = targetGrid.length, m = targetGrid[0].length;
Set<Integer> colors = new HashSet<>();
Map<Integer, int[]> bounds = new HashMap<>(); // minRow, maxRow, minCol, maxCol
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
int c = targetGrid[i][j];
colors.add(c);
if (!bounds.containsKey(c)) {
bounds.put(c, new int[]{i, i, j, j});
} else {
int[] arr = bounds.get(c);
arr[0] = Math.min(arr[0], i);
arr[1] = Math.max(arr[1], i);
arr[2] = Math.min(arr[2], j);
arr[3] = Math.max(arr[3], j);
}
}
}
Map<Integer, Set<Integer>> graph = new HashMap<>();
Map<Integer, Integer> indegree = new HashMap<>();
for (int c : colors) {
int[] bound = bounds.get(c);
int minR = bound[0], maxR = bound[1], minC = bound[2], maxC = bound[3];
for (int i = minR; i <= maxR; ++i) {
for (int j = minC; j <= maxC; ++j) {
int cc = targetGrid[i][j];
if (cc != c) {
if (!graph.containsKey(c)) graph.put(c, new HashSet<>());
if (!graph.get(c).contains(cc)) {
graph.get(c).add(cc);
indegree.put(cc, indegree.getOrDefault(cc, 0) + 1);
}
}
}
}
}
Queue<Integer> q = new LinkedList<>();
for (int c : colors) {
if (!indegree.containsKey(c) || indegree.get(c) == 0) q.add(c);
}
Set<Integer> removed = new HashSet<>();
while (!q.isEmpty()) {
int c = q.poll();
removed.add(c);
if (graph.containsKey(c)) {
for (int nei : graph.get(c)) {
indegree.put(nei, indegree.get(nei) - 1);
if (indegree.get(nei) == 0) q.add(nei);
}
}
}
return removed.size() == colors.size();
}
}
var isPrintable = function(targetGrid) {
let n = targetGrid.length, m = targetGrid[0].length;
let colors = new Set();
let bounds = new Map(); // color: [minRow, maxRow, minCol, maxCol]
for (let i = 0; i < n; ++i) {
for (let j = 0; j < m; ++j) {
let c = targetGrid[i][j];
colors.add(c);
if (!bounds.has(c)) {
bounds.set(c, [i, i, j, j]);
} else {
let arr = bounds.get(c);
arr[0] = Math.min(arr[0], i);
arr[1] = Math.max(arr[1], i);
arr[2] = Math.min(arr[2], j);
arr[3] = Math.max(arr[3], j);
}
}
}
let graph = new Map();
let indegree = new Map();
for (let c of colors) {
let [minR, maxR, minC, maxC] = bounds.get(c);
for (let i = minR; i <= maxR; ++i) {
for (let j = minC; j <= maxC; ++j) {
let cc = targetGrid[i][j];
if (cc !== c) {
if (!graph.has(c)) graph.set(c, new Set());
if (!graph.get(c).has(cc)) {
graph.get(c).add(cc);
indegree.set(cc, (indegree.get(cc) || 0) + 1);
}
}
}
}
}
let queue = [];
for (let c of colors) {
if (!indegree.has(c) || indegree.get(c) === 0) queue.push(c);
}
let removed = new Set();
while (queue.length) {
let c = queue.shift();
removed.add(c);
if (graph.has(c)) {
for (let nei of graph.get(c)) {
indegree.set(nei, indegree.get(nei) - 1);
if (indegree.get(nei) === 0) queue.push(nei);
}
}
}
return removed.size === colors.size;
};
targetGrid
, a 2D matrix of integers, where each integer represents a color. The grid starts blank. You have a printer that can print a solid rectangle of any color, but each print can only cover a rectangle and will overwrite existing colors. The objective is to determine whether it is possible to print the targetGrid
using a sequence of such rectangle prints, with the constraint that each color can be used any number of times, but the rectangle for each color must cover all instances of that color in the final grid in a single print (i.e., you cannot print the same color in two separate, non-overlapping rectangles).
Key constraints:
targetGrid
.targetGrid
:
[ [1,1,2], [1,1,2], [3,3,2] ]