Before attempting this problem, you should be comfortable with:
An island in grid2 is a sub-island if every land cell of that island is also land in grid1. We can use DFS to explore each island in grid2 and simultaneously check if all its cells correspond to land in grid1. If any cell in the island exists in grid2 but not in grid1, the entire island is disqualified. We must explore the complete island before deciding, so we continue the DFS even after finding a mismatch.
grid2, start a DFS.true if out of bounds, on water, or already visited (base cases).grid1 has land at this position; if not, the result becomes false.class Solution:
def countSubIslands(self, grid1: List[List[int]], grid2: List[List[int]]) -> int:
ROWS, COLS = len(grid1), len(grid1[0])
visit = set()
def dfs(r, c):
if (min(r, c) < 0 or r == ROWS or c == COLS or
grid2[r][c] == 0 or (r, c) in visit):
return True
visit.add((r, c))
res = grid1[r][c]
res &= dfs(r - 1, c)
res &= dfs(r + 1, c)
res &= dfs(r, c - 1)
res &= dfs(r, c + 1)
return res
count = 0
for r in range(ROWS):
for c in range(COLS):
if grid2[r][c] and (r, c) not in visit:
count += dfs(r, c)
return countWhere is the number of rows and is the number of columns.
Similar to DFS, we can use BFS to explore islands in grid2. Starting from any unvisited land cell, we use a queue to visit all connected land cells level by level. During the traversal, we check if each cell also exists as land in grid1. If any cell fails this check, the island is not a sub-island, but we continue exploring to mark all cells as visited.
grid2, start a BFS.true.grid1 has water at this position, set result to false.grid2 to the queue and mark them visited.class Solution:
def countSubIslands(self, grid1: List[List[int]], grid2: List[List[int]]) -> int:
ROWS, COLS = len(grid1), len(grid1[0])
visit = [[False] * COLS for _ in range(ROWS)]
directions = [1, 0, -1, 0, 1]
def bfs(r, c):
queue = deque([(r, c)])
visit[r][c] = True
res = True
while queue:
r, c = queue.popleft()
if grid1[r][c] == 0:
res = False
for i in range(4):
nr, nc = r + directions[i], c + directions[i + 1]
if 0 <= nr < ROWS and 0 <= nc < COLS and not visit[nr][nc] and grid2[nr][nc]:
visit[nr][nc] = True
queue.append((nr, nc))
return res
count = 0
for r in range(ROWS):
for c in range(COLS):
if grid2[r][c] == 1 and not visit[r][c]:
if bfs(r, c):
count += 1
return countWhere is the number of rows and is the number of columns.
We can use Union-Find to group connected land cells in grid2 into islands. The key insight is that we also create a special "invalid" node (indexed at N, where N is the total number of cells). Any land cell in grid2 that corresponds to water in grid1 gets unioned with this invalid node. After processing, the number of sub-islands equals the total land cells minus the number of union operations performed (since each union either merges two components or marks one as invalid).
N+1 nodes (N cells plus one invalid node).grid2:grid2.grid2.grid1 has water at this position, union this cell with the invalid node N.class DSU:
def __init__(self, n):
self.Parent = list(range(n + 1))
self.Size = [1] * (n + 1)
def find(self, node):
if self.Parent[node] != node:
self.Parent[node] = self.find(self.Parent[node])
return self.Parent[node]
def union(self, u, v):
pu = self.find(u)
pv = self.find(v)
if pu == pv:
return False
if self.Size[pu] < self.Size[pv]:
pu, pv = pv, pu
self.Size[pu] += self.Size[pv]
self.Parent[pv] = pu
return True
class Solution:
def countSubIslands(self, grid1, grid2):
ROWS, COLS = len(grid1), len(grid1[0])
N = ROWS * COLS
dsu = DSU(N)
def getId(r, c):
return r * COLS + c
land = unions = 0
for r in range(ROWS):
for c in range(COLS):
if not grid2[r][c]:
continue
land += 1
if r + 1 < ROWS and grid2[r + 1][c]:
unions += dsu.union(getId(r, c), getId(r + 1, c))
if c + 1 < COLS and grid2[r][c + 1]:
unions += dsu.union(getId(r, c), getId(r, c + 1))
if not grid1[r][c]:
unions += dsu.union(getId(r, c), N)
return land - unionsWhere is the number of rows and is the number of columns.
A critical mistake is returning false immediately when finding a cell that exists in grid2 but not in grid1. This leaves part of the island unexplored and unvisited, causing those cells to be counted as separate islands later.
# Wrong: Early return leaves island partially visited
if grid1[r][c] == 0:
return False # Other cells in this island won't be marked
# Correct: Continue exploring, track result with a variable
res = grid1[r][c] == 1
res &= dfs(r - 1, c) # Must visit all cellsWhen combining results from the four directional DFS calls, using OR (|) instead of AND (&) will incorrectly mark an island as a sub-island if any single cell matches, rather than requiring all cells to match.
When deciding whether to explore a neighboring cell, the check must be against grid2 (where we're finding islands), not grid1. The grid1 check determines validity, but grid2 determines connectivity.