[leetcode] 305. Number of Islands II

原题

给定 n,m,分别代表一个2D矩阵的行数和列数,同时,给定一个大小为 k 的二元数组A。起初,2D矩阵的行数和列数均为 0,即该矩阵中只有海洋。二元数组有 k 个运算符,每个运算符有 2 个整数 A[i].x, A[i].y,你可通过改变矩阵网格中的A[i].x],[A[i].y] 来将其由海洋改为岛屿。请在每次运算后,返回矩阵中岛屿的数量。

样例
给定 n = 3, m = 3, 二元数组 A =[(0,0),(0,1),(2,2),(2,1)].
返回 [1,1,2,2].

解题思路

  • 作为Number of Islands的follow up,可以同样使用DFS或者BFS,每次加入新的点就再全部遍历一次二维数组 - 每次遍历O(mn),如果一共k次操作,总的时间复杂度为O(km*n)
  • 由于每次操作只是把一块海洋变成陆地,它影响的点只可能是上下左右四个位置,如果是1,将它们合并。
  • 集合合并 - 使用并查集,换句话说只有可能改变四个点的father
  • 初始化时,每个点的father是自己的ID = x*列数 + y
  • 全局变量 count = 0, 每次增加一个点 count += 1
  • 考虑上下左右四个位置是否能够合并,每次合并 count -= 1
  • 最终时间复杂度降为O(k*4) ~ O(k)

完整代码

# Definition for a point.
# class Point:
#     def __init__(self, a=0, b=0):
#         self.x = a
#         self.y = b
class UnionFind:
    def __init__(self, m, n):
        self.father = {}
        for i in range(n):
            for j in range(m):
                id = self.converttoId(i,j,m);
                self.father[id] = id 

    def converttoId(self, x, y, m):
        return x*m + y
        
    def find(self, x):
            parent = self.father[x]
            while parent != self.father[parent]:
                parent = self.father[parent]
            return parent
        
    def compressed_find(self, x):
        parent = self.father[x]
        while parent != self.father[parent]:
            parent = self.father[parent]

        temp = -1;
        fa = self.father[x]
        while fa != self.father[fa]:
            temp = self.father[fa]
            self.father[fa] = parent
            fa = temp

        return parent

        
    def union(self, x, y):
            fa_x = self.find(x)
            fa_y = self.find(y)
            if fa_x != fa_y:
                self.father[fa_x] = fa_y
                
class Solution:
    # @param {int} n an integer
    # @param {int} m an integer
    # @param {Pint[]} operators an array of point
    # @return {int[]} an integer array
    def numIslands2(self, n, m, operators):
        dx = [0,-1, 0, 1]
        dy = [1, 0, -1, 0]
        island = [[0 for i in range(m)] for j in range(n)]
        ans = []
        uf = UnionFind(n, m)
        count = 0
        if operators != None:
            for i in range(len(operators)):
                count += 1
                x = operators[i].x
                y = operators[i].y
                if island[x][y] != 1:
                    island[x][y]  = 1
                    id = uf.converttoId(x, y, m)
                    # 计算上下左右四个点的位置
                    for j in range(4):
                        nx = x + dx[j]
                        ny = y + dy[j]
                        if 0 <= nx and nx < n and 0 <= ny and ny < m and island[nx][ny] == 1:
                            nid = uf.converttoId(nx, ny, m)
                            fa = uf.find(id)
                            nfa = uf.find(nid)
                            if fa != nfa:
                                count -= 1
                                uf.union(id, nid)

                ans.append(count)
            return ans


作者:Jason_Yuan
链接:https://www.jianshu.com/p/2867b84e2a38
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:([leetcode] 305. Number of Islands II)