给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:
11110
11010
11000
00000
输出: 1
示例 2:
输入:
11000
11000
00100
00011
输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。
一开始想到的也是深度优先算法,但是额外开辟了一块空间来记录标记,其实只要在原来的空间里把”1”改成”0”就可以了
广度优先算法和深度优先算法都差不多,遇到”1”后把周围所有的”1”都标记成”0”,并且结果岛屿数+1
解法1:深度优先搜索
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
if not grid:
return 0
i, j = 0, 0
cnt = 0
def mark(x, y):
if grid[x][y] == "0":
return
if grid[x][y] == "1":
grid[x][y] = "0"
if (x + 1) < len(grid):
mark(x+1, y)
if (x - 1) >= 0:
mark(x-1, y)
if (y + 1) < len(grid[0]):
mark(x, y+1)
if (y - 1) >= 0:
mark(x, y-1)
while i < len(grid):
j = 0
while j < len(grid[i]):
if grid[i][j] == "1":
mark(i, j)
cnt += 1
j += 1
i += 1
return cnt
时间复杂度:O(MN) 每一个元素只需要遍历一遍
空间复杂度:O(MN) 栈的深度 在最坏情况下,整个网格均为陆地,深度优先搜索的深度达到 MN
解法2:广度优先搜索
使用队列来循环构建标记(直接复制的官方解法)
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
nr = len(grid)
if nr == 0:
return 0
nc = len(grid[0])
num_islands = 0
for r in range(nr):
for c in range(nc):
if grid[r][c] == "1":
num_islands += 1
grid[r][c] = "0"
neighbors = collections.deque([(r, c)])
while neighbors:
row, col = neighbors.popleft()
for x, y in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:
if 0 <= x < nr and 0 <= y < nc and grid[x][y] == "1":
neighbors.append((x, y))
grid[x][y] = "0"
return num_islands
时间复杂度:O(MN)
空间复杂度:O(min(M, N)) 队列的长度,不知道怎么算的。。。
解法3:并查集
为所有值为”1”的索引创建并查集,遍历所有元素,遇到”1”后union周围所有1,返回并查集里的集合个数即可
官方解法
class UnionFind:
def __init__(self, grid):
m, n = len(grid), len(grid[0])
self.count = 0
self.parent = [-1] * (m * n)
self.rank = [0] * (m * n)
for i in range(m):
for j in range(n):
if grid[i][j] == "1":
self.parent[i * n + j] = i * n + j
self.count += 1
def find(self, i):
if self.parent[i] != i:
self.parent[i] = self.find(self.parent[i])
return self.parent[i]
def union(self, x, y):
rootx = self.find(x)
rooty = self.find(y)
if rootx != rooty:
if self.rank[rootx] < self.rank[rooty]:
rootx, rooty = rooty, rootx
self.parent[rooty] = rootx
if self.rank[rootx] == self.rank[rooty]:
self.rank[rootx] += 1
self.count -= 1
def getCount(self):
return self.count
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
nr = len(grid)
if nr == 0:
return 0
nc = len(grid[0])
uf = UnionFind(grid)
num_islands = 0
for r in range(nr):
for c in range(nc):
if grid[r][c] == "1":
grid[r][c] = "0"
for x, y in [(r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)]:
if 0 <= x < nr and 0 <= y < nc and grid[x][y] == "1":
uf.union(r * nc + c, x * nc + y)
return uf.getCount()