【网格问题】【并查集】leetcode 305.岛屿数量 II

461 篇文章 1 订阅
125 篇文章 2 订阅

题目:
假设你设计一个游戏,用一个 m 行 n 列的 2D 网格来存储你的游戏地图。

起始的时候,每一个格子的地形都被默认标记为「水」。咱们能够经过使用 addLand 进行操作,将位置 (row, col) 的「水」变成「陆地」。

你将会被给定一个列表,来记录全部须要被操作的位置,而后你须要返回计算出来 每次 addLand 操作后岛屿的数量。

注意:一个岛的定义是被「水」包围的「陆地」,经过水平方向或者垂直方向上相邻的陆地链接而成。

输入:m = 3, n = 3, positions = [[0,0],[0,1],[1,2],[2,1]]
输出:[1,1,2,3]
解释:
起初,二维网格 grid 被全部注入「水」。(0 代表「水」,1 代表「陆地」)
- 操作 #1:addLand(0, 0) 将 grid[0][0] 的水变为陆地。此时存在 1 个岛屿。
- 操作 #2:addLand(0, 1) 将 grid[0][1] 的水变为陆地。此时存在 1 个岛屿。
- 操作 #3:addLand(1, 2) 将 grid[1][2] 的水变为陆地。此时存在 2 个岛屿。
- 操作 #4:addLand(2, 1) 将 grid[2][1] 的水变为陆地。此时存在 3 个岛屿。

在这里插入图片描述
思路:
并查集:
parent:字典,记录父子关系
cnt:记录并查集的个数

解答:

class UF:
    def __init__(self, M):
        #字典,记录父子关系:{儿子:父亲}
        self.parent = {}
        # cnt:表示并查集中的集合个数
        self.cnt = 0

    #将idx加入并查集中
    def add(self,idx):
        if idx not in self.parent:
            self.parent[idx]=idx
            self.cnt+=1

    # 判断x所属集合
    def find(self, x):
        while x != self.parent[x]:
            x = self.parent[x]
        return x

    # 合并p和q所在的集合,新元素所在集合纳入旧元素所在集合中
    def union(self, p, q):
        if self.connected(p, q):
            return
        set_p = self.find(p)
        set_q = self.find(q)
        if set_p!=set_q:
            self.parent[set_p]=set_q
            self.cnt-=1

    # 判断两元素是否属于同一集合
    def connected(self, p, q):
        return self.find(p) == self.find(q)

#填海造陆,0海,1陆
class Solution:
    def numIsLand2(self,m,n,positions):
        def index(i,j):
            return i*n+j

        dir = [[-1, 0], [1, 0], [0, -1], [0, 1]]
        grid=[[0]*n for _ in range(m)]
        uf=UF(m*n)
        res=[]
        for x,y in positions:
            cur=index(x,y)
            uf.add(cur)
            for dx,dy in dir:
                ng=index(x+dx,y+dy)
                #如果邻居已被填为大陆,则将当前元素合并到邻居中
                if ng in uf.parent:
                    uf.union(cur,ng)
            res.append(uf.cnt)
        return res


if __name__=='__main__':
    solution=Solution()
    m,n=3,3
    positions=[[0,0],[0,1],[1,2],[2,1]]
    res=solution.numIsLand2(m,n,positions)
    print(res)

思维扩展1:
如果要返回每个岛屿的大小,则并查集需要新增一个size.
示例返回:[[1, [1]], [1, [2]], [2, [2, 1]], [3, [2, 1, 1]]]

class UF:
    def __init__(self, M):
        #字典,记录父子关系{儿子:父亲}
        self.parent = {}
        #size:记录集合大小{元素:元素集合(包含当前元素及其孩子)的大小}
        self.size={}
        # cnt:表示并查集中的集合个数
        self.cnt = 0

    #将idx加入并查集中
    def add(self,idx):
        if idx not in self.parent:
            self.parent[idx]=idx
            self.size[idx]=1
            self.cnt+=1

    # 判断x所属集合
    def find(self, x):
        while x != self.parent[x]:
            x = self.parent[x]
        return x

    # 合并p和q所在的集合,新元素所在集合纳入旧元素所在集合中
    def union(self, p, q):
        if self.connected(p, q):
            return
        set_p = self.find(p)
        set_q = self.find(q)
        if set_p!=set_q:
            self.parent[set_p]=set_q
            self.size[set_q]+=self.size[set_p]
            self.cnt-=1

    # 判断两元素是否属于同一集合
    def connected(self, p, q):
        return self.find(p) == self.find(q)

#填海造陆,0海,1陆
class Solution:
    def numIsLand2(self,m,n,positions):
        def index(i,j):
            return i*n+j

        dir = [[-1, 0], [1, 0], [0, -1], [0, 1]]
        grid=[[0]*n for _ in range(m)]
        uf=UF(m*n)
        res=[]
        for x,y in positions:
            cur=index(x,y)
            uf.add(cur)
            for dx,dy in dir:
                ng=index(x+dx,y+dy)
                #如果邻居已被填为大陆,则将当前元素合并到邻居中
                if ng in uf.parent:
                    uf.union(cur,ng)
            print(uf.parent,uf.size,uf.cnt)
            landArea=sorted(uf.size.values(),key=lambda x:-x)
            landNum=uf.cnt
            #res中的每一项代表:[当前岛屿个数,每个岛屿的大小]
            res.append([landNum,landArea[:landNum]])
        return res


if __name__=='__main__':
    solution=Solution()
    m,n=3,3
    positions=[[0,0],[0,1],[1,2],[2,1]]
    res=solution.numIsLand2(m,n,positions)
    print(res)

思维扩展2:
返回岛屿个数,即每个岛屿的岛主和岛屿大小
示例返回:[[1, [(0, 1)]], [1, [(0, 2)]], [2, [(0, 2), (5, 1)]], [3, [(0, 2), (5, 1), (7, 1)]]]

class UF:
    def __init__(self, M):
        #字典,记录父子关系{儿子:父亲}
        self.parent = {}
        #size:记录集合大小{元素:元素集合(包含当前元素及其孩子)的大小}
        self.size={}
        # cnt:表示并查集中的集合个数
        self.cnt = 0

    #将idx加入并查集中
    def add(self,idx):
        if idx not in self.parent:
            self.parent[idx]=idx
            self.size[idx]=1
            self.cnt+=1

    # 判断x所属集合
    def find(self, x):
        while x != self.parent[x]:
            x = self.parent[x]
        return x

    # 合并p和q所在的集合,新元素所在集合纳入旧元素所在集合中
    def union(self, p, q):
        if self.connected(p, q):
            return
        set_p = self.find(p)
        set_q = self.find(q)
        if set_p!=set_q:
            self.parent[set_p]=set_q
            self.size[set_q]+=self.size[set_p]
            self.cnt-=1

    # 判断两元素是否属于同一集合
    def connected(self, p, q):
        return self.find(p) == self.find(q)

#填海造陆,0海,1陆
class Solution:
    # 方法1:返回[(岛主,对应岛屿的大小)]
    # 直接按岛屿大小降序排序,返回符合要求的前uf.cnt的即可
    def getLandInfo1(self,uf):
        # 按岛屿大小降序排列
        landArea = sorted(uf.size.items(), key=lambda x: -x[1])
        tmp = []  # 记录岛主及其岛屿面积的大小
        while len(tmp) != uf.cnt:
            for landRoot, area in landArea:
                if uf.find(landRoot) == landRoot:
                    tmp.append((landRoot, area))
        return tmp

    #方法2:返回[(岛主,对应岛屿的大小)]
    #需要对父子集合遍历并判断,若当前元素为岛主,即加入结果集。结果集大小等于uf.cnt时即可返回
    def getLandInfo2(self,uf):
        tmp=[]
        for son,parent in uf.parent.items():
            if son==parent:
                tmp.append((parent,uf.size[parent]))
            if len(tmp)==uf.cnt:
                break
        return tmp


    def numIsLand2(self,m,n,positions):
        def index(i,j):
            return i*n+j

        dir = [[-1, 0], [1, 0], [0, -1], [0, 1]]
        grid=[[0]*n for _ in range(m)]
        uf=UF(m*n)
        ans=[]
        for x,y in positions:
            cur=index(x,y)
            uf.add(cur)
            for dx,dy in dir:
                ng=index(x+dx,y+dy)
                #如果邻居已被填为大陆,则将当前元素合并到邻居中
                if ng in uf.parent:
                    uf.union(cur,ng)
            #cur_landInfo=self.getLandInfo1(uf)
            cur_landInfo = self.getLandInfo2(uf)
            ans.append([uf.cnt,cur_landInfo])
            #print(ans)
        return ans


if __name__=='__main__':
    solution=Solution()
    m,n=3,3
    positions=[[0,0],[0,1],[1,2],[2,1]]
    ans=solution.numIsLand2(m,n,positions)
    print(ans)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值