forked from kamyu104/LeetCode-Solutions
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstrange-printer-ii.py
89 lines (80 loc) · 3.38 KB
/
strange-printer-ii.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# Time: O(c * m * n + e), c is the number of colors
# , e is the number of edges in adj, at most O(c^2)
# Space: O(e)
import collections
class Solution(object):
def isPrintable(self, targetGrid):
"""
:type targetGrid: List[List[int]]
:rtype: bool
"""
VISITING, VISITED = range(2)
def has_cycle(adj, color, lookup):
stk = [(1, color)]
while stk:
step, color = stk.pop()
if step == 1:
lookup[color] = VISITING
stk.append((2, color))
for new_color in adj[color]:
if new_color in lookup:
if lookup[new_color] == VISITED:
continue
return True # VISITING
stk.append((1, new_color))
elif step == 2:
lookup[color] = VISITED
return False
boxes = collections.defaultdict(lambda:[len(targetGrid), len(targetGrid[0]), -1, -1])
for r, row in enumerate(targetGrid):
for c, color in enumerate(row):
boxes[color][0] = min(boxes[color][0], r)
boxes[color][1] = min(boxes[color][1], c)
boxes[color][2] = max(boxes[color][2], r)
boxes[color][3] = max(boxes[color][3], c)
adj = collections.defaultdict(set)
for color, (min_r, min_c, max_r, max_c) in boxes.iteritems():
for r in xrange(min_r, max_r+1):
for c in xrange(min_c, max_c+1):
if targetGrid[r][c] != color:
adj[color].add(targetGrid[r][c])
lookup = {}
return all(color in lookup or not has_cycle(adj, color, lookup) for color in boxes.iterkeys())
# Time: O(c * m * n + e), c is the number of colors
# , e is the number of edges in adj, at most O(c^2)
# Space: O(e)
class Solution2(object):
def isPrintable(self, targetGrid):
"""
:type targetGrid: List[List[int]]
:rtype: bool
"""
VISITING, VISITED = range(2)
def has_cycle(adj, color, lookup):
lookup[color] = VISITING
for new_color in adj[color]:
if (new_color not in lookup and has_cycle(adj, new_color, lookup)) or \
lookup[new_color] == VISITING:
return True
lookup[color] = VISITED
return False
MAX_COLOR = 60
adj = collections.defaultdict(set)
for color in xrange(1, MAX_COLOR+1):
min_r = len(targetGrid)
min_c = len(targetGrid[0])
max_r = -1
max_c = -1
for r in xrange(len(targetGrid)):
for c in xrange(len(targetGrid[r])):
if targetGrid[r][c] == color:
min_r = min(min_r, r)
min_c = min(min_c, c)
max_r = max(max_r, r)
max_c = max(max_c, c)
for r in xrange(min_r, max_r+1):
for c in xrange(min_c, max_c+1):
if targetGrid[r][c] != color:
adj[color].add(targetGrid[r][c])
lookup = {}
return all(color in lookup or not has_cycle(adj, color, lookup) for color in xrange(1, MAX_COLOR+1))