1591. 奇怪的打印机 II
大约 3 分钟
--- 

1591. 奇怪的打印机 II
- 标签:图、拓扑排序、数组、矩阵
- 难度:困难
题目链接
题目大意
描述:给定一个 的矩阵 ,每个位置有颜色值 。有一台打印机,每次操作可以选择一种颜色,将该颜色的一个连通区域(矩形区域)涂满该颜色,可以覆盖之前的颜色。
要求:判断是否能通过若干次操作得到 。
说明:
- 。
示例:
- 示例 1:

输入:targetGrid = [[1,1,1,1],[1,2,2,1],[1,2,2,1],[1,1,1,1]]
输出:true- 示例 2:

输入:targetGrid = [[1,1,1,1],[1,1,3,3],[1,1,3,4],[5,5,1,4]]
输出:true解题思路
思路 1:拓扑排序
1. 核心思想
对于每种颜色 ,找到它在 中出现的边界(最上、最下、最左、最右)。这个边界矩形范围内的所有格子,要么是颜色 ,要么是在 之上涂的其他颜色。
这意味着边界矩形内不是 的颜色必须在 之后涂。这构成一个偏序关系。
如果这个偏序关系有环(循环依赖),则不可能得到目标矩阵。
2. 具体步骤
第 1 步:找到每种颜色的边界 。
第 2 步:遍历矩阵,对于每种颜色 的边界矩形内:
- 如果某个格子的颜色 ,添加一条边 (表示 先涂, 后涂)。
第 3 步:拓扑排序。如果存在环,返回 False,否则 True。
3. 举例说明
以 为例:
颜色 的边界 ,边界矩形内有颜色 (在 区域),说明 必须在 之前涂。
颜色 的边界 ,边界矩形内只有 。
拓扑排序:,无环,返回 True。
以 为例:
颜色 的边界 ,矩形内有颜色 ,。
颜色 的边界 ,矩形内有颜色 ,。
存在环 ,返回 False。
思路 1:代码
class Solution:
def isPrintable(self, targetGrid: List[List[int]]) -> bool:
m, n = len(targetGrid), len(targetGrid[0])
# 每种颜色的边界
bound = {}
for i in range(m):
for j in range(n):
c = targetGrid[i][j]
if c not in bound:
bound[c] = [i, i, j, j] # min_r, max_r, min_c, max_c
else:
bound[c][0] = min(bound[c][0], i)
bound[c][1] = max(bound[c][1], i)
bound[c][2] = min(bound[c][2], j)
bound[c][3] = max(bound[c][3], j)
# 建图:c -> other,表示 c 必须在 other 之前
graph = {c: set() for c in bound}
indeg = {c: 0 for c in bound}
for c, (min_r, max_r, min_c, max_c) in bound.items():
for i in range(min_r, max_r + 1):
for j in range(min_c, max_c + 1):
other = targetGrid[i][j]
if other != c and other not in graph[c]:
graph[c].add(other)
indeg[other] = indeg.get(other, 0) + 1
# 拓扑排序
from collections import deque
q = deque([c for c in bound if indeg.get(c, 0) == 0])
cnt = 0
while q:
c = q.popleft()
cnt += 1
for nxt in graph[c]:
indeg[nxt] -= 1
if indeg[nxt] == 0:
q.append(nxt)
return cnt == len(bound)思路 1:复杂度分析
- 时间复杂度:,最多 。
- 空间复杂度:。