305. Number of Islands II - Explanation

Problem Link

Description

You are given an empty 2D binary grid grid of size m x n. The grid represents a map where 0's represent water and 1's represent land. Initially, all the cells of grid are water cells (i.e., all the cells are 0's).

We may perform an add land operation which turns the water at position into a land. You are given an array positions where positions[i] = [rᵢ, cᵢ] is the position (rᵢ, cᵢ) at which we should operate the ith operation.

Return an array of integers answer where answer[i] is the number of islands after turning the cell (rᵢ, cᵢ) into a land.

An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.

Example 1:

Input: m = 3, n = 3, positions = [[0,0],[0,1],[1,2],[2,1]]

Output: [1,1,2,3]

Explanation:
Initially, the 2d grid is filled with water.

  • Operation #1: addLand(0, 0) turns the water at grid[0][0] into a land. We have 1 island.
  • Operation #2: addLand(0, 1) turns the water at grid[0][1] into a land. We still have 1 island.
  • Operation #3: addLand(1, 2) turns the water at grid[1][2] into a land. We have 2 islands.
  • Operation #4: addLand(2, 1) turns the water at grid[2][1] into a land. We have 3 islands.

Example 2:

Input: m = 1, n = 1, positions = [[0,0]]

Output: [1]

Constraints:

  • 1 <= m, n, positions.length <= 10⁴
  • 1 <= m * n <= 10⁴
  • positions[i].length == 2
  • 0 <= rᵢ < m
  • 0 <= cᵢ < n

Follow up: Could you solve it in time complexity O(k log(mn)), where k == positions.length?


Company Tags


1. Union Find

class UnionFind:
    def __init__(self, size):
        self.parent = [-1] * size
        self.rank = [0] * size
        self.count = 0
    
    def add_land(self, x):
        if self.parent[x] >= 0:
            return
        self.parent[x] = x
        self.count += 1
    
    def is_land(self, x):
        if self.parent[x] >= 0:
            return True
        else:
            return False
    
    def number_of_islands(self):
        return self.count
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        xset = self.find(x)
        yset = self.find(y)
        
        if xset == yset:
            return
        elif self.rank[xset] < self.rank[yset]:
            self.parent[xset] = yset
        elif self.rank[xset] > self.rank[yset]:
            self.parent[yset] = xset
        else:
            self.parent[yset] = xset
            self.rank[xset] += 1
        
        self.count -= 1


class Solution:
    def numIslands2(self, m: int, n: int, positions: List[List[int]]) -> List[int]:
        x = [-1, 1, 0, 0]
        y = [0, 0, -1, 1]
        dsu = UnionFind(m * n)
        answer = []
        
        for position in positions:
            land_position = position[0] * n + position[1]
            dsu.add_land(land_position)
            
            for i in range(4):
                neighbor_x = position[0] + x[i]
                neighbor_y = position[1] + y[i]
                neighbor_position = neighbor_x * n + neighbor_y
                
                # If neighborX and neighborY correspond to a point in the grid and there is a
                # land at that point, then merge it with the current land.
                if neighbor_x >= 0 and neighbor_x < m and neighbor_y >= 0 and neighbor_y < n and dsu.is_land(neighbor_position):
                    dsu.union(land_position, neighbor_position)
            
            answer.append(dsu.number_of_islands())
        
        return answer

Time & Space Complexity

  • Time complexity: O(mn+l)O(m \cdot n + l)
  • Space complexity: O(mn)O(m \cdot n)

Where mm and nn are the number of rows and columns in the given grid, and ll is the size of positions.