【力扣】200岛屿数量

目录

一、题目

二、并查集思路

2.1、代码实现

2.2、思路总结

三、BFS思路

3.1代码实现

3.2思路总结


一、题目

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。


示例 1:

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

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

提示:

m == grid.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j] 的值为 '0' 或 '1'


二、并查集思路

2.1、代码实现

2.1.1代码解析

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        row = len(grid)
        res =0
        cow = len(grid[0])
        ufs = UFS(grid,row,cow)
        for p in range(row):
            for q in range(cow):
                if grid[p][q] == "1": #从这个1进来之后一整片同一区域为“1”的都会被找到后清零
                    grid[p][q] = "0" #记得走过要清零,不然会多走
                    for x,y in [(p,q-1),(p,q+1),(p-1,q),(p+1,q)]: #当前方块的上下左右寻找为1的
                        if 0 <= x < row and 0 <= y < cow and grid[x][y] == "1": #要避免超出边界
                            ufs.union((p,q),(x,y)) #找到了就两两联系
                    
        for k in ufs.father: #将其遍历
            if k == ufs.father[k]: #里面值相同的就是一整个区域的1的最终父节点(一整片区域只有一个父节点)
                res += 1 #找到了多存在一个区域
        return res
        
class UFS:
    def __init__(self,grid,row,cow):
        self.father = {}
        for i in range(row):
            for j in range(cow):
                if grid[i][j] == "1":
                    self.father[(i,j)] = (i,j)

    def find(self,node):
        father = self.father[node]
        if father == node:
            return node
        else:
            father = self.find(father) #这里差一个father赋值(记差了)
            return father

    def union(self,node_a,node_b): 
        root_a = self.find(node_a)
        root_b = self.find(node_b)
        self.father[root_b] = root_a 

 

2.2、思路总结

2.2.1并查集的核心思想

class UFS:
    def __init__(self,isConnected):
        self.father = {} #设置一个字典装每个结点的父节点
        for i in range(len(isConnected)): 
            self.father[i] = i #一开始将数组的父节点都指向自身

    def find(self,node):  #找父节点
        father = self.father[node] #当前node点的父节点起名为father
        if father == node: #如果结点指向本身了说明已经达到父节点了
            return node
        else:
            father = self.find(father) #不然找他父亲的父节点
            return father

    def union(self,node_a,node_b): #传入两个节点建立联系
        root_a = self.find(node_a) #找到node_a的父节点
        root_b = self.find(node_b) #找到node_b的父节点
        self.father[root_b] = root_a #将root_a作为root_b的父节点建立联系

2.2.2 在init中可以调整指向的父节点是一个元组还是一个值

  • 对于二维数组为了最后的结果可以自身到自身的数量(相当于一个相邻区域的结束标志),因为没有相连的一个独立个体“0”也会有自身到自身
    def __init__(self,grid,row,cow):
        self.father = {}
        for i in range(row):
            for j in range(cow):
                if grid[i][j] == "1":
                    self.father[(i,j)] = (i,j) #传入的是元组

 我会选择这样去剔除干扰选项,具体操作因为题而异

如 :蓝桥杯的合根植物,就需要保留所有自身到自身的数据,因而不能剔除

  • 对于二位数组同样也可以指向父节点为一个值,将下标从左到右、从上到下,从0开始依次排列到a,找到横列纵列下标与a之间的关系

        将a与a' 作为节点之间的联系

    def __init__(self, grid):
        m, n = len(grid), len(grid[0])
        self.count = 0
        self.parent = [-1] * (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
    

 

三、BFS思路

3.1代码实现

3.1.1 代码解析(走过的路设置为0避免重复)

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        row = len(grid)
        cow = len(grid[0])
        res = 0
        queue = []
        for i in range(row):
            for j in range(cow):
                if grid[i][j] == "1": #找到一个为1就进入循环
                    queue.append((i,j))
                    grid[i][j] = "0"
                    while len(queue) > 0: #在这个循环中即为BFS将一整块为1的地方全都遍历出来
                        nr,nw = queue.pop() #下一级元素都找出加入queue后队头可以pop
                        for x,y in [(nr,nw-1),(nr,nw+1),(nr-1,nw),(nr+1,nw)]:
                            if 0 <= x < row and 0 <= y < cow and grid[x][y] == "1": #防超出限制
                                queue.append((x,y)) #把队头的下一级都找出来
                                grid[x][y] = "0" #走过的地方要记得清零,避免死循环
                    res += 1 #进入这个if能找出一板块1,题目要求有多少块
        return res

 

3.1.2代码解析(走过的路加入到元组中避免重复走)

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        row = len(grid)
        cow = len(grid[0])
        res = 0
        queue = []
        seen = set() #利用集合不重复的特性存放走过的路径
        for i in range(row):
            for j in range(cow):
                if grid[i][j] == "1" and (i,j) not in seen: #找到为1且不在没走过的地
                    queue.append((i,j)) 
                    while len(queue) > 0:
                        nr,nw = queue.pop()
                        for x,y in [(nr,nw-1),(nr,nw+1),(nr-1,nw),(nr+1,nw)]:
                            if 0 <= x < row and 0 <= y < cow and grid[x][y] == "1":
                                if (x,y) not in seen: #如果没有走过就走一走
                                    queue.append((x,y)) 
                                    seen.add((x,y)) #同时也要放入已走过的seen里面
                    res += 1
        return res

3.2思路总结

3.2.1 走过的路记得清零

就算用集合去存放已经走过的路,在上下左右寻找的时候也需要清零,否则死循环

3.2.2 seen在append之前一定要判断

避免走过的路再走也死循环

3.3.3 BFS核心

  • 两层循环遍历
  • seen或者设为0把控不走重复路
  • 遵照BFS队头pop出去找刚pop的队头下一级的节点,直到queue完时,就已经走完一大片为1的地方
  • pop队头后要找下一级节点通过for循环上下左右得到,将得到的节点作为下一级放入queue

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值