-
Notifications
You must be signed in to change notification settings - Fork 90
/
Number of Islands II.py
127 lines (100 loc) · 3.54 KB
/
Number of Islands 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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
"""
Given a n,m which means the row and column of the 2D matrix and an array of pair A( size k). Originally, the 2D matrix
is all 0 which means there is only sea in the matrix. The list pair has k operator and each operator has two integer
A[i].x, A[i].y means that you can change the grid matrix[A[i].x][A[i].y] from sea to island. Return how many island are
there in the matrix after each operator.
Example
Given n = 3, m = 3, array of pair A = [(0,0),(0,1),(2,2),(2,1)].
return [1,1,2,2].
Note
0 is represented as the sea, 1 is represented as the island. If two 1 is adjacent, we consider them in the same island.
We only consider up/down/left/right adjacent.
"""
import random
__author__ = 'Daniel'
class Point(object):
def __init__(self, a=0, b=0):
self.x = a
self.y = b
def __repr__(self):
return "[%d, %d]" % (self.x, self.y)
class UnionFind(object):
"""
Weighted Union Find with path compression
"""
def __init__(self, rows, cols):
# hashing will cause TLE; use direct array access instead
self.pi = [-1 for _ in xrange(rows*cols)] # item -> pi
self.sz = [-1 for _ in xrange(rows*cols)] # root -> size
self.count = 0
def add(self, item):
if self.pi[item] == -1:
self.pi[item] = item
self.sz[item] = 1
self.count += 1
def union(self, a, b):
pi1 = self._pi(a)
pi2 = self._pi(b)
if pi1 != pi2:
if self.sz[pi1] > self.sz[pi2]:
pi1, pi2 = pi2, pi1
self.pi[pi1] = pi2
self.sz[pi2] += self.sz[pi1]
self.count -= 1
def _pi(self, item):
pi = self.pi[item]
if item != pi:
self.pi[item] = self._pi(pi)
return self.pi[item]
class Solution:
def __init__(self):
self.dirs = ((-1, 0), (1, 0), (0, -1), (0, 1))
def numIslands2(self, n, m, operators):
"""
:type n: int
:type m: int
:type operators: list[Point]
:rtype: list[int]
"""
rows = n
cols = m
unroll = lambda x, y: x*cols+y # hash will be slower
mat = [[0 for _ in xrange(cols)] for _ in xrange(rows)]
uf = UnionFind(rows, cols)
ret = []
for op in operators:
uf.add(unroll(op.x, op.y))
mat[op.x][op.y] = 1
for dir in self.dirs:
x1 = op.x+dir[0]
y1 = op.y+dir[1]
if 0 <= x1 < rows and 0 <= y1 < cols and mat[x1][y1] == 1:
uf.union(unroll(op.x, op.y), unroll(x1, y1))
ret.append(uf.count)
return ret
class TestCaseGenerator(object):
def _generate(self):
dim = 10
m = random.randrange(1, dim)
n = random.randrange(1, dim)
k = random.randrange(1, max(2, m*n/3))
operators = []
visited = set()
while len(operators) < k:
p = random.randrange(m*n)
if p not in visited:
x = p/n
y = p%n
operators.append(Point(x, y))
visited.add(p)
print(m)
print(n)
print(operators)
def generate(self, T=50):
for _ in xrange(T):
self._generate()
if __name__ == "__main__":
assert Solution().numIslands2(3, 3, map(lambda x: Point(x[0], x[1]), [(0, 0), (0, 1), (2, 2), (2, 1)])) == [1, 1, 2,
2]
testcase = TestCaseGenerator()
testcase.generate()