[Leetcode] 305. Number of Islands II 解题报告

题目

A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand operation which turns the water at position (row, col) into a land. Given a list of positions to operate, count the number of islands after each addLand operation. 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:

Given m = 3, n = 3positions = [[0,0], [0,1], [1,2], [2,1]].
Initially, the 2d grid grid is filled with water. (Assume 0 represents water and 1 represents land).

0 0 0
0 0 0
0 0 0

Operation #1: addLand(0, 0) turns the water at grid[0][0] into a land.

1 0 0
0 0 0   Number of islands = 1
0 0 0

Operation #2: addLand(0, 1) turns the water at grid[0][1] into a land.

1 1 0
0 0 0   Number of islands = 1
0 0 0

Operation #3: addLand(1, 2) turns the water at grid[1][2] into a land.

1 1 0
0 0 1   Number of islands = 2
0 0 0

Operation #4: addLand(2, 1) turns the water at grid[2][1] into a land.

1 1 0
0 0 1   Number of islands = 3
0 1 0

We return the result as an array: [1, 1, 2, 3]

Challenge:

Can you do it in time complexity O(k log mn), where k is the length of the positions?

思路

这是一道合并-查找题目(Union-Find)题目,这类题目的实现也具有一定套路,值得总结:

1)为每个位置初始化一个父结点。因为是一个二维数组,比较方便的做法是将二维数组映射到一维,我们采用的方法是将 (x, y) 的父结点映射到 (x * n + y)。

2)每次插入一个新元素时,查找其上下左右地图是不是有相邻的陆地(当然在此之前需要建立一张二维的地图,并随着插入新元素而不断更新该地图)。

3)默认情况下,新添加一个点小岛的数量就增加1,然而如果这个新添加的陆地有相邻的陆地,就需要将其合并成一块陆地,此时小岛数量减1。上下左右四个方向,每次合并一个邻接点,小岛的数量都要减1。

我觉得这里查找parents的代码比较关键,建议读者理解并且记下来。

代码

class Solution {
public:
    vector<int> numIslands2(int m, int n, vector<pair<int, int>>& positions) {
        vector<vector<int>> island(m, vector<int>(n, 0));   
        vector<int> result;
        int num = 0;
        vector<int> parents(m * n);                         // record the root of each position using 1D array
        for(int i = 0; i < m * n; ++i) {
            parents[i] = i;
        }            
        vector<pair<int, int>> directions{{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
        for(auto val : positions) {                         // for each added island
            for(auto val2 : directions) {                   // for each direction
                int x = val.first, y = val.second;
                int px = x + val2.first, py = y + val2.second;
                if(px < 0 || px >= m || py < 0 || py >= n || island[px][py] == 0) {
                    continue;
                }
                // par1 is the central point, and par2 is the neighboring point, we map them to 1D array
                int par1 = x * n + y, par2 = px * n + py;
                while(par1 != parents[par1]) {              // do not change anything, just reach to its ancester
                    parents[par1] = parents[parents[par1]];
                    par1 = parents[par1];
                }
                while(par2 != parents[par2]) {              // do not change anything, just reach to its ancester
                    parents[par2] = parents[parents[par2]];
                    par2 = parents[par2];
                }
                if(par1 != par2) {
                    parents[par2] = par1;
                    --num;
                }
            }
            island[val.first][val.second] = 1;
            result.push_back(++num);
        }
        return result;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值