LT200. 岛屿数量-按微软以及出现频率刷LT题

LT200. 岛屿数量

出题指数五颗星,出现频率极高

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成
此外,你可以假设该网格的四条边均被水包围

例子

输入:grid = [
  ["1","1","1","1","0"],
  ["1","1","0","1","0"],
  ["1","1","0","0","0"],
  ["0","0","0","0","0"]
]
输出:1

输入:grid = [
  ["1","1","0","0","0"],
  ["1","1","0","0","0"],
  ["0","0","1","0","0"],
  ["0","0","0","1","1"]
]
输出:3

这道题可以用广度优先搜索和深度优先搜索的方法来做。
首先对这两种搜索方法进行理解

(1)广度优先搜索bfs 会根据离起点的距离,按照从近到远的顺序对各节点进行搜索。
广度优先搜索中,有一个保存候补节点的队列,队列的性质就是先进先出,即先进入该队列的候补节点就先进行搜索。
借助例子解释一下:
下图中红色表示当前所在的节点(节点A),终点设为节点G,将与节点A直连的三个节点B, C, D放入存放候补节点的队列中(与节点A直连的三个节点放入时可以没有顺序,这里的放入顺序为B, C, D),用绿色表示:
请添加图片描述
此时队列有 [B, C, D],都是与A直接相连的。本着先进先出的原则,先把B弹出,然后找寻跟B相连的节点。跟B相连有E和F,所以把E和F录入,则此时队列为 [C,D,E,F], 继续下去,把C弹出,然后把C相连的节点H录入,此时队列是 [D, E, F, H], 还是没找到要找的G节点,于是继续弹出与录入,继续弹出D,录入与D相连的I和J,此时队列是 [E, F, H, I, J], 继续弹出E, 录入K, 得到[F, H, I, J, K], 弹出F,无录入节点,弹出H,录入G,此刻队列是[I, J, K, G]. 找到G节点。结束。

广度优先搜索为从起点开始,由近及远进行广泛的搜索。因此,目标节点离起点越近,搜索结束得就越快。

(2)深度优先搜索dfs 会沿着一条路径不断往下搜索直到不能再继续为止,然后再折返,开始搜索下一条路径。深度优先搜索中,保存候补节点是栈,栈的性质就是先进后出。
也是上面那个例子做解释
在这里插入图片描述

还是将起点设为节点A,终点设为节点G,先录入A相连的节点,假设录入的顺序是 D,C,B,栈是[D, C, B], 本着先进后出的原则。 先弹出的是B,录入的是E和F。此刻栈是 [D, C, F, E] 然后继续弹出E,录入K,栈为 [D, C, F, K], 继续弹出K,无相连节点,弹出F,无相连节点。此时栈为 [D, C], 弹出C,录入H,此时栈为 [D, H], 弹出H,录入G,此时找到G了。 结束。

上面👆就是两种方法的搜寻方式,一个优先搜索宽度,一个优先搜索深度。

回到LT题目。
(1)使用广度优先搜索方法-bfs
从坐标(0,0) 开始搜寻,如果是1的话,把其相邻坐标都搜做一遍,并把同样为1的坐标录入队列。队列的搜索方式先进先出。不断地弹出,录入内容为1的坐标,直到队列为空。
【录入队列的时候,会顺便把录入的坐标内容从1都会被重新标记为 0,表示已经搜索过,不需再重新搜索录入】
最后岛屿的数量就是我们进行广度优先搜索的次数

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        num_r = len(grid)
        if num_r == 0:
            return 0 
        num_c = len(grid[0])
        ans = 0      
        for r in range(num_r):
            for c in range(num_c):
                if grid[r][c] == "1":
                    ans += 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)]:
                        #对其邻边的内容进行搜索,如果内容为1,则进行录入,并修改为0
                            if 0 <= x < num_r and 0 <= y < num_c and grid[x][y] == "1":
                                neighbors.append((x, y))
                                grid[x][y] = "0"      
        return ans

时间复杂度:O(MN); 空间复杂度:O(min(M,N))

(2)使用深度优先搜索-dfs
同理,dfs也是差不多的原理,只不过dfs会针对一个节点,不断滴进行探索,直到没有内容为1的坐标。
即如果一个位置为 11,则以其为起始节点开始进行深度优先搜索。并且在搜索的过程中,每个搜索过的1都会被重新标记为 0。

class Solution:
    def dfs(self, grid, r, c):
        #把搜索过的坐标内容重新标识为0
        grid[r][c] = 0 
        num_c = len(grid)
        if num_c ==0:return 0
        num_r = len(grid[0])
        for x,y in [(r-1,c),(r+1,c),(r,c-1),(r,c+1)]:
            if 0<=x<num_c and 0<= y < num_r and grid[x][y] =='1':
                self.dfs(grid,x,y)

    def numIslands(self, grid: List[List[str]]) -> int:
        num_c = len(grid)
        if num_c ==0:return 0
        num_r = len(grid[0])
        ans = 0 
        for c in range(num_c):
            for r in range(num_r):
                if grid[c][r] == '1':
                    ans+= 1 
                    self.dfs(grid,c,r)
        return ans 

时间复杂度:O(MN)
空间复杂度:O(MN)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jianafeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值