岛屿问题通解——网格DFS(深度优先搜索)问题
超赞的总结
200. 岛屿数量
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
def dfs(grid, i, j):
if not 0<=i<len(grid) or not 0<=j<len(grid[0]): # 或的关系
return
if grid[i][j] != '1':
return
# 当前格子是陆地且未被遍历过
grid[i][j] = 2 # 2标记该格子已被遍历过
dfs(grid, i-1, j)
dfs(grid, i+1, j)
dfs(grid, i, j+1)
dfs(grid, i, j-1)
count = 0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == '1': # 注意 这里是字符 不是整数
dfs(grid, i, j)
count += 1
return count
# grid是可变对象,其在函数内的改变会影响函数外的对象
463. 岛屿的周长
陆地于海洋的交界处会有一条边长——遇到海洋返回1
class Solution:
def islandPerimeter(self, grid: List[List[int]]) -> int:
# 发现规律 遇到一个海洋返回1
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j]==1:
return self.dfs(grid, i, j)
def dfs(self, grid, i, j):
if not 0<=i<len(grid) or not 0<=j<len(grid[0]): # 超过网格界 及遇到水域
return 1
if grid[i][j]==0: # 遇到水域
return 1
if grid[i][j] == 2: # 当前格子已遍历过 对周长无贡献 不能直接return 否则为None,不能于整数相加
return 0
grid[i][j] = 2 # 对遍历过的格子进行标记
return self.dfs(grid, i+1, j)+self.dfs(grid,i-1,j)+self.dfs(grid, i, j+1)+self.dfs(grid, i, j-1)
695. 岛屿的最大面积
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
# 在200岛屿数量基础上 还要统计每个岛屿的面积 取最大
maxArea = 0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 1:
curArea = self.dfs(grid, i, j)
maxArea = max(curArea, maxArea)
return maxArea
def dfs(self, grid, i, j):
if not 0<=i<len(grid) or not 0<=j<len(grid[0]):
return 0
if grid[i][j] != 1:
return 0
grid[i][j] = 2
return 1+ self.dfs(grid, i+1, j)+ self.dfs(grid, i-1, j)+ self.dfs(grid, i, j+1)+ self.dfs(grid, i, j-1)
827. 最大人工岛
分析:
①使用数组记录每个岛屿的序号及面积 若三个岛屿分别为2,3,4(岛屿从2开始编号,避免和陆地1混淆),面积分别为3,5,2,则可使用哈希表{2:3,3:5,4:2}
②先得到每个岛屿的面积,然后遍历网格内的海洋,填当前海洋得到的最大岛屿面积等于1+相邻岛屿的面积(注意不要重复,一个海洋的四边相邻的岛屿可能会是同一个)
class Solution:
def largestIsland(self, grid: List[List[int]]) -> int:
global n
n = len(grid)
# 函数——求岛屿面积
def islandArea(grid, i,j,mark):
if not 0<=i<n or not 0<=j<n:
return 0
if grid[i][j] != 1: # 已被遍历过或是海洋
return 0
grid[i][j] = mark # 对当前岛屿的陆地进行标记
return 1+islandArea(grid, i+1, j, mark)+islandArea(grid, i-1, j, mark)+islandArea(grid, i, j+1, mark)+islandArea(grid, i, j-1, mark)
# 求人工填海后获得的面积
def manIslandArea(grid, i, j, hp):
cover = [] # 记录已遍历过的岛屿
newarea = 1 # 要加上当前填海的面积
for ni,nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: # 向与当前海洋相邻的四个方向找寻岛屿
if 0<=ni<n and 0<=nj<n and grid[ni][nj] not in cover and grid[ni][nj] in hp:
newarea += hp[grid[ni][nj]]
cover.append(grid[ni][nj])
return newarea
# 遍历岛屿 求出每个岛屿的面积
hp = {}
mark = 2 # 岛屿的标记 从2开始
allland = True
for i in range(n):
for j in range(n):
if grid[i][j] == 1:
area = islandArea(grid,i,j,mark)
hp[mark] = area
mark += 1 # 更新标签
# 遍历海洋 求出填每个海洋得到的岛屿面积
curMax = 0
for i in range(n):
for j in range(n):
if grid[i][j] == 0:
allland = False
manArea = manIslandArea(grid, i, j, hp)
curMax = max(manArea, curMax)
if allland: # 全为陆地 这种情况要单独讨论 否则输出为0
return n*n
return curMax # 有海洋