Number of Islands II

Given a n,m which means the row and column of the 2D matrix and an array of pair A( size k). Originally, the 2D matrix is all 0 which means there is only sea in the matrix. The list pair has k operator and each operator has two integer A[i].x, A[i].y means that you can change the grid matrix[A[i].x][A[i].y] from sea to island. Return how many island are there in the matrix after each operator.

先给出二维矩阵的行列值,之后再给出一系列操作数目,每个操作是在一个位置插入岛屿。和Number of Islands这种先给出全部岛屿布图不一样,这种情景下更适合使用并查集,因为预先给出岛屿分布,还是无法确定操作的数目,需要扫描二维矩阵,判断为1的地方进行操作。反而使用DFS更方便一些。这题每次加入一个一个岛屿相当于新加入一个集合。之后判断这个新加岛屿上下左右是否有岛屿,如果存在的话,进行集合的合并,把当前岛屿加入,并减少岛屿的个数。

# Definition for a point.
# class Point:
#     def __init__(self, a=0, b=0):
#         self.x = a
#         self.y = b

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):
        if not m or not n or not operators:
            return []
        UF = UnionFind()
        res = []
        for p  in  map(lambda a: (a.x, a.y), operators):
            UF.add(p)
            for dx in (1, 0), (0, 1), (-1, 0), (0, -1):
                q =  (dx[0] + p[0], dx[1]+p[1])
                if q in UF.id:
                    UF.union(p,q)
            res += [UF.count]
        return res
                    
class UnionFind(object):
    def __init__(self):
        self.id = {} #object
        self.sz = {} #object'weight, size here.
        self.count = 0
        
    def add(self, p):
        self.id[p] = p
        self.sz[p] = 1
        self.count += 1
        
    def find(self, i):
        while i!= self.id[i]:
            self.id[i] = self.id[self.id[i]] #路径压缩
            i = self.id[i]
        return i

    def union(self, p, q):
        i = self.find(p)
        j = self.find(q)
        if i == j:
            return
        if self.sz[i] > self.sz[j]: #union is only operated on heads按秩合并
            i, j = j, i
        self.id[i] = j
        self.sz[i] += self.sz[j]
        self.count -= 1

以上操作的最多合并次数为4k次,object k个。所以时间复杂度为O((4k+k)log*k).log*为迭代次数,不超过5,所以时间复杂度为O(k)大小。空间复杂度为两个dict(权重和father),O(k)大小。由于key值是tuple,空间消耗非常大,所以这种解法在lintcode上MLE. 可以每次将二维坐标转化为一维坐标来做键值。 

Leetcode版本解法: 二维坐标转化为一维数字的表达,一定要注意乘的是列数不是行数!!

class Solution(object):
    def numIslands2(self, m, n, positions):
        """
        :type m: int
        :type n: int
        :type positions: List[List[int]]
        :rtype: List[int]
        """
        #union find method
        #union find init function, find function, union function,add function the basic architecture is hashmap.
        #extra space-saving method, turn the 2D coordinates into 1D, multiply the number of column not row
        res = []
        delta = [1,0,-1,0,1]
        UF = UnionFind()
        for a in positions:
            UF.add(a[0]*n + a[1])
            for i in xrange(4):
                x = a[0] + delta[i]
                y = a[1] + delta[i+1]
                p = x*n+y
                if 0 <= x < m and 0 <= y < n and p in  UF.root:
                    UF.union(a[0]*n + a[1], p)
            res.append(UF.cnt)
        return res
class UnionFind(object):
    def __init__(self):
        self.root = {}
        self.sz = {}
        self.cnt = 0
    def add(self, x):
        self.root[x] = x
        self.sz[x] = 1
        self.cnt += 1
    def find(self, x): #find the root of a node
        while x!= self.root[x]:
            self.root[x] = self.root[self.root[x]]
            x = self.root[x]
        return x
    def union(self, x, y): #attention, just union the big brother, link smaller union to the larger one
        i = self.find(x)
        j = self.find(y)
        if i != j: #not in the same union
            if self.sz[i] > self.sz[j]:
                self.root[j] = i
                self.sz[i] += self.sz[j]
            else:
                self.root[i] = j
                self.sz[j] += self.sz[i]
            self.cnt -= 1
            
        
原文地址:https://www.cnblogs.com/sherylwang/p/5576007.html