Skip to content

Commit 40bb7c2

Browse files
committed
docs: Add docstrings and doctests for Matrix methods
- Added descriptive docstrings for Matrix, is_safe, count_islands, and diffs methods - Added doctests covering both normal and edge cases for all methods - Improves didactic quality and test coverage
1 parent 29afed0 commit 40bb7c2

1 file changed

Lines changed: 130 additions & 14 deletions

File tree

matrix/count_islands_in_matrix.py

Lines changed: 130 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,88 @@
1-
# An island in matrix is a group of linked areas, all having the same value.
2-
# This code counts number of islands in a given matrix, with including diagonal
3-
# connections.
1+
class Matrix:
2+
"""
3+
Class to represent a 2D grid as a matrix and count the number of islands.
4+
An island is a group of connected 1s (connections can be vertical, horizontal, or diagonal).
5+
"""
46

5-
6-
class Matrix: # Public class to implement a graph
77
def __init__(self, row: int, col: int, graph: list[list[bool]]) -> None:
8+
"""
9+
Initialize the matrix.
10+
11+
:param row: Number of rows
12+
:param col: Number of columns
13+
:param graph: 2D list representing the matrix (1 = land, 0 = water)
14+
15+
>>> graph = [[1, 1, 0], [0, 1, 0], [1, 0, 0]]
16+
>>> m = Matrix(3, 3, graph)
17+
>>> m.ROW
18+
3
19+
>>> m.COL
20+
3
21+
>>> m.graph == graph
22+
True
23+
24+
# Edge case: Empty matrix
25+
>>> empty = Matrix(0, 0, [])
26+
>>> empty.ROW
27+
0
28+
>>> empty.COL
29+
0
30+
>>> empty.graph
31+
[]
32+
33+
# Edge case: 1x1 matrix
34+
>>> single = Matrix(1, 1, [[1]])
35+
>>> single.ROW
36+
1
37+
>>> single.COL
38+
1
39+
>>> single.graph
40+
[[1]]
41+
"""
42+
843
self.ROW = row
944
self.COL = col
1045
self.graph = graph
1146

47+
48+
1249
def is_safe(self, i: int, j: int, visited: list[list[bool]]) -> bool:
50+
"""
51+
Check if a cell (i, j) is "safe".
52+
53+
We consider a cell "safe" if:
54+
- It is within the bounds of the matrix
55+
- It has not been visited yet
56+
- It contains land (i.e., value is nonzero)
57+
58+
:param i: row index
59+
:param j: column index
60+
:param visitied: 2D list indicating which cells we have visited
61+
:return: True if cell is safe, else False
62+
63+
>>> m = Matrix(3, 3, [[1, 0, 0], [0, 0, 1]])
64+
>>> visited = [[False]*3 for _ in range(3)]
65+
66+
# Within bounds, unvisited, and value is 1 (land)
67+
>>> m.is_safe(0, 0, visited)
68+
True
69+
70+
# Within bounds, unvisited, but value is 0 (water)
71+
>>> m.is_safe(0, 1, visited)
72+
False
73+
74+
# Within bounds, already visited
75+
>>> visited[0][0] = True
76+
>>> m.is_safe(0, 0, visited)
77+
False
78+
79+
# Out of bounds
80+
>>> m.is_safe(3, 0, visited)
81+
False
82+
>>> m.is_safe(-1, 0, visited)
83+
False
84+
"""
85+
1386
return (
1487
0 <= i < self.ROW
1588
and 0 <= j < self.COL
@@ -18,20 +91,63 @@ def is_safe(self, i: int, j: int, visited: list[list[bool]]) -> bool:
1891
)
1992

2093
def diffs(self, i: int, j: int, visited: list[list[bool]]) -> None:
21-
# Checking all 8 elements surrounding nth element
22-
row_nbr = [-1, -1, -1, 0, 0, 1, 1, 1] # Coordinate order
94+
"""
95+
Depth-first search (DFS) to mark all land cells (1s) connected to (i, j) as visited.
96+
97+
:param i: Row index of current cell
98+
:param j: Column index of current cell
99+
:param visited: 2D list tracking visited cells
100+
101+
diffs() checks the 8 cells surrounding the current cell (i, j) and marks the land cells as visited.
102+
103+
>>> graph = [[1, 1, 0], [0, 1, 0], [0, 0, 1]]
104+
>>> m = Matrix(3, 3, graph)
105+
>>> visited = [[False] * 3 for _ in range(3)]
106+
>>> m.diffs(0, 0, visited)
107+
>>> visited[0][0] and visited[0][1] and visited[1][1]
108+
True
109+
>>> visited[2][2]
110+
False
111+
"""
112+
113+
# 8 possible movements (N, NE, E, SE, S, SW, W, NW)
114+
row_nbr = [-1, -1, -1, 0, 0, 1, 1, 1]
23115
col_nbr = [-1, 0, 1, -1, 1, -1, 0, 1]
24-
visited[i][j] = True # Make those cells visited
116+
117+
# Make cells visited
118+
visited[i][j] = True
25119
for k in range(8):
26-
if self.is_safe(i + row_nbr[k], j + col_nbr[k], visited):
27-
self.diffs(i + row_nbr[k], j + col_nbr[k], visited)
120+
next_i, next_j = i + row_nbr[k], j + col_nbr[k]
121+
if self.is_safe(next_i, next_j, visited):
122+
self.diffs(next_i, next_j, visited)
123+
124+
def count_islands(self) -> int:
125+
"""
126+
Count the number of islands in the matrix.
28127
29-
def count_islands(self) -> int: # And finally, count all islands.
30-
visited = [[False for j in range(self.COL)] for i in range(self.ROW)]
128+
:return: Number of islands found
129+
130+
>>> graph[[1, 1, 0], [0, 1, 0], [1, 0, 0]]
131+
>>> m = Matrix(3, 3, graph)
132+
>>> m.count_islands()
133+
2
134+
135+
>>> graph2 = [[0, 0, 0], [0, 0, 0]]
136+
>>> m2 = Matrix(2, 3, graph2)
137+
>>> m2.count_islands()
138+
0
139+
140+
>>> graph3 = [[1]]
141+
>>> m3 = Matrix(1, 1, graph3)
142+
>>> m3.count_islands()
143+
1
144+
"""
145+
visited = [[False for _ in range(self.COL)] for _ in range(self.ROW)]
31146
count = 0
32147
for i in range(self.ROW):
33148
for j in range(self.COL):
34-
if visited[i][j] is False and self.graph[i][j] == 1:
149+
if not visited[i][j] and self.graph[i][j] == 1:
35150
self.diffs(i, j, visited)
36-
count += 1
151+
count += 1
37152
return count
153+

0 commit comments

Comments
 (0)