[LeetCode305]Number of Islands II

Hard..

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 = 3, positions = [[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?

Hide Company Tags Google
Hide Tags Union Find
Hide Similar Problems (M) Number of Islands

我好討厭union find啊。。。

這道題還要繼續理解一下, 等我懂了再來說一說。

class UnionFind2D {
public:
    UnionFind2D(int m, int n) {
        for (int i = 0; i < m * n; i++) ids.push_back(-1);
        for (int i = 0; i < m * n; i++) szs.push_back(1);
        M = m, N = n, cnt = 0;
    }
    int index(int x, int y) {
        return x * N + y;
    }
    int size(void) {
        return cnt;
    }
    int id(int x, int y) {
        if (x >= 0 && x < M && y >= 0 && y < N)
            return ids[index(x, y)];
        return -1;
    }
    int add(int x, int y) {
        int idx = index(x, y);
        ids[idx] = idx;
        szs[idx] = 1;
        cnt++;
        return idx;
    }
    int root(int i) {
        for (; i != ids[i]; i = ids[i])
            ids[i] = ids[ids[i]];
        return i;
    }
    bool find(int p, int q) {
        return root(p) == root(q);
    }
    void unite(int p, int q) {
        int i = root(p), j = root(q);
        if (szs[i] > szs[j]) swap(i, j);
        ids[i] = j;
        szs[j] += szs[i];
        cnt--;
    }
private:
    vector<int> ids, szs;
    int M, N, cnt;
};

class Solution {
public:
    vector<int> numIslands2(int m, int n, vector<pair<int, int>>& positions) {
        UnionFind2D islands(m, n);
        vector<pair<int, int>> dirs = { { 0, -1 }, { 0, 1 }, { -1, 0 }, { 1, 0 } };
        vector<int> ans;
        for (auto& pos : positions) {
            int x = pos.first, y = pos.second;
            int p = islands.add(x, y);
            for (auto& d : dirs) {
                int q = islands.id(x + d.first, y + d.second);
                if (q >= 0 && !islands.find(p, q))
                    islands.unite(p, q);
            }
            ans.push_back(islands.size());
        }
        return ans;
    }
};

12/15/2015 update:

上面那個code 是path compression的( 2116 ms),自己寫了個沒有path compression的能過,但很慢。。2504 ms
基本思想就是把2d展開成1d每個點都有自己的idx,然後利用普通的union find做。。。就是找root, root不一樣就可以合併並且減少cnt初始值,(隱含着root一樣已經在一個group裏了,不需要減少cnt值。。) 因爲此時我們cnt的初始值設置的是:假設當前island跟之前所有的都是獨立的,就是res.back()+1. 記得update roots。

code 如下:

class Solution {
public:
    int findRoot(int i, vector<int>& roots){
        if(roots[i] == i) return i;
        return findRoot(roots[i], roots);
    }

    vector<int> numIslands2(int m, int n, vector<pair<int, int>>& positions) {
        vector<int> res;
        vector<int> roots(m*n, -1);
        vector<pair<int, int>> dirs = {{1,0}, {-1,0}, {0,1}, {0,-1}};
        for(auto p : positions){
            int x = p.first, y = p.second;
            int idx = x * n + y;
            roots[idx] = idx;
            int cnt = res.empty() ? 1 : res.back() + 1;//initial islands number as individual one!
            for(auto d : dirs){
                int newX = x + d.first, newY = y + d.second;
                int newIdx = newX * n + newY;
                if(newX >=0 && newX < m && newY >=0 && newY < n && roots[newIdx] != -1){//only try to union island, -1 means water
                    int root1 = findRoot(newIdx, roots);
                    int root2 = idx;
                    if(root1 != root2) --cnt;// current island can connect with its neighbors.
                                                //if root1 == root2 means they already in same group we dont need decrease the cnt.
                    roots[root1] = root2;
                }
            }
            for(int i = 0; i<roots.size(); ++i){
                    cout<<i<<"=>"<<roots[i]<<",";
                }
                cout<<endl;
            res.push_back(cnt);
        }
        return res;
    }
};

再貼一下這個slides:
https://www.cs.princeton.edu/~rs/AlgsDS07/01UnionFind.pdf

還有time complexity 分析:
啊啊啊啊爲什麼我不會啊!煩躁
https://leetcode.com/discuss/69392/python-clear-solution-unionfind-class-weighting-compression

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章