一.问题描述
Given a 2D grid
consists of 0s
(land) and 1s
(water). An island is a maximal 4-directionally connected group of 0s
and a closed island is an island totally (all left, top, right, bottom) surrounded by 1s.
Return the number of closed islands.
Example 1:
Input: grid = [[1,1,1,1,1,1,1,0],[1,0,0,0,0,1,1,0],[1,0,1,0,1,1,1,0],[1,0,0,0,0,1,0,1],[1,1,1,1,1,1,1,0]]
Output: 2
Explanation:
Islands in gray are closed because they are completely surrounded by water (group of 1s).
Example 2:
Input: grid = [[0,0,1,0,0],[0,1,0,1,0],[0,1,1,1,0]]
Output: 1
Example 3:
Input: grid = [[1,1,1,1,1,1,1],
[1,0,0,0,0,0,1],
[1,0,1,1,1,0,1],
[1,0,1,0,1,0,1],
[1,0,1,1,1,0,1],
[1,0,0,0,0,0,1],
[1,1,1,1,1,1,1]]
Output: 2
Constraints:
1 <= grid.length, grid[0].length <= 100
0 <= grid[i][j] <=1
二.解题思路
对于这道题来说,如果是closed的就说明某一区域所有连通的0被1包围了。
其实相当于我们在求0-连通图的数量,并且这个连通图不依赖于矩阵的边界。
求连通图的数量一般都是用深度优先搜索。
对于图的深度优先搜索,得记录已访问过的节点变量,防止死循环或死递归。同时记录已处理过的连通图(如果一个连通图已处理过,我们需要将有一种方法记录该连通图已处理过,防止重复处理)。
因为在一个连通图中若某一个点是open或者closed的,那么整个连通图都是open或者closed的。
最简单的方法就是在深度优先搜索时,如果当前节点grid[x][y]为0,把其设置为1以表示该点已访问过。这种做法并不影响其他点的深度优先搜索的结果并能同时满足深度优先搜索的实现要求,和表示该点在连通图中已处理过。
同时我们需要有一个变量来记录深度优先搜索的结果(如果用函数返回值来做会比较麻烦,因为对当前dfs的返回值来说,得考虑4个方向上的返回结果,而python的and和or操作是短路逻辑,会导致我们之前说的grid[i][j]从0设置为1表示已访问的方法出现问题,可能导致整个连通图只部分处理,比如果在某一个方向上已确定它是opened的,其他方向都不处理的,那么只在此方向上搜索的点变成了1已访问,然而其他方向上的点没变化,相当于把这个非封闭的缺口堵上了,之后我们再访问这个连通图未被处理的部分会导致其变为封闭图。要避免这个问题就得用4个变量记录4个方向的返回结果然后再比较,很麻烦,不如直接一个类变量来的舒服)。
深度优先搜索的策略:
1.如果当前点超过边界,说明该连通图不closed。更改结果并返回。
2.如果当前点值为1,返回
3.如果当前点值为0,更改为1表示已访问已处理,递归4个方向上的深度优先搜索。
现在具体来讲:
1.我们对每个grid[i][j]为0的点执行深度优先搜索。
2.有一个类变量isopened来记录深度优先搜索的结果,isopened默认为false,如果在深度优先搜索中某个点超出了边界(说明某个边界有0,这个连通图不是closed的),执行完深度优先搜索后,如果isopened为false,将计数器+1,封闭连通图数量+1。
时间复杂度O(mn), n,m是grid的行和列数。
更多leetcode算法题解法: 专栏 leetcode算法从零到结束
三.源码
class Solution:
isopened=False
def closedIsland(self, grid: List[List[int]]) -> int:
n,m,res=len(grid),len(grid[0]),0
for i in range(n):
for j in range(m):
if grid[i][j]==0:
self.isopened=False
self.DFS(grid,i,j,n,m)
if not self.isopened:res+=1
return res
def DFS(self,grid,x,y,n,m):
if x<0 or y<0 or x>=n or y>=m:
self.isopened=True
return
if grid[x][y]==1: return
grid[x][y]=1
self.DFS(grid,x-1,y,n,m),self.DFS(grid,x+1,y,n,m),self.DFS(grid,x,y-1,n,m), self.DFS(grid,x,y+1,n,m)