美文网首页LeetCode
Leetcode 947 Most Stones Removed

Leetcode 947 Most Stones Removed

作者: lee_5a30 | 来源:发表于2018-11-25 12:01 被阅读0次

    1. 数岛屿问题

    如果两个石头在同行或者同列,两个石头就是连接的。连在一起的石头,可以组成一个连通图。每一个连通图至少会剩下1个石头。
    所以我们希望存在一种思路,每个连通图都只剩下1个石头。
    这样这题就转化成了数岛屿的问题。

    2. 朴素DFS

    实际上做这道题,你并不需要去构造或者证明,移走石头的方案。有了step1里的思路,已经足够用dfs来解决这个问题了。

        def removeStones(self, points):
            rows = collections.defaultdict(set)
            cols = collections.defaultdict(set)
            for i, j in points:
                rows[i].add(j)
                cols[j].add(i)
    
            def dfsRow(i):
                seenR.add(i)
                for j in rows[i]:
                    if j not in seenC:
                        dfsCol(j)
    
            def dfsCol(j):
                seenC.add(j)
                for i in cols[j]:
                    if i not in seenR:
                        dfsRow(i)
    
            seenR, seenC = set(), set()
            islands = 0
            for i, j in points:
                if i not in seenR:
                    islands += 1
                    dfsRow(i)
                    dfsCol(j)
            return len(points) - islands
    

    3. 优化行列处理

    上述代码有很多冗余,实际上我们对行列的搜索,没有任何本质区别。
    只不过是因为同一个index,可能是行也可能是列,所以我们做了区分。
    实际上,只要我们能区分行列的index,代码就可以缩减一半了。

    行的index我们还可以用0~N - 1,列的index我们使用N~2N-1就可以了。

        def removeStones(self, points):
            index = collections.defaultdict(set)
            for i, j in points:
                index[i].add(j + 10000)
                index[j + 10000].add(i)
    
            def dfs(i):
                seen.add(i)
                for j in index[i]:
                    if j not in seen:
                        dfs(j)
    
            seen = set()
            islands = 0
            for i, j in points:
                if i not in seen:
                    islands += 1
                    dfs(i)
                    dfs(j + 10000)
            return len(points) - islands
    

    4. 换个思考角度

    我们之前的思路是,对石头所在point进行搜索。
    有了以上代码,我们就会发现,其实我们搜索的元素是行列的index。

    我们以为是行列把石头连接在了一起。
    换个角度思考,也可以是一个石头把它所在行列坐标连在了一起。

    我们的输入是所有的石头,每个石头都固定连接两个元素。
    想到这里,union find的思路就已经呼之欲出了。

    C++:

        int removeStones(vector<vector<int>>& stones) {
            for (int i = 0; i < stones.size(); ++i)
                uni(stones[i][0], ~stones[i][1]);
            return stones.size() - islands;
        }
    
        unordered_map<int, int> f;
        int islands = 0;
    
        int find(int x) {
            if (!f.count(x)) f[x] = x, islands++;
            if (x != f[x]) f[x] = find(f[x]);
            return f[x];
        }
    
        void uni(int x, int y) {
            x = find(x), y = find(y);
            if (x != y) f[x] = y, islands--;
        }
    

    Java:

        Map<Integer, Integer> f = new HashMap<>();
        int islands = 0;
    
        public int removeStones(int[][] stones) {
            for (int i = 0; i < stones.length; ++i)
                union(stones[i][0], ~stones[i][1]);
            return stones.length - islands;
        }
    
        public int find(int x) {
            if (f.putIfAbsent(x, x) == null)
                islands++;
            if (x != f.get(x))
                f.put(x, find(f.get(x)));
            return f.get(x);
        }
    
        public void union(int x, int y) {
            x = find(x);
            y = find(y);
            if (f.get(x) != y) {
                f.put(find(x), find(y));
                islands--;
            }
        }
    

    Python:

        def removeStones(self, points):
            UF = {}
            def find(x):
                if x != UF[x]:
                    UF[x] = find(UF[x])
                return UF[x]
            def union(x, y):
                UF.setdefault(x, x)
                UF.setdefault(y, y)
                UF[find(x)] = find(y)
    
            for i, j in points:
                union(i, ~j)
            return len(points) - len({find(x) for x in UF})
    

    5. 构造移走石头方案

    逆向思维,来看一下,如果开始只有一个石头,每次都只能放一个新石头在同行或同列,我们能否构造出整个岛屿。
    还是不难得,可以用dfs里查找石头的顺序放,就可以构造整个岛屿了。
    反之,按照反序也可以移走整个岛屿直到剩下一个石头。

    相关文章

      网友评论

        本文标题:Leetcode 947 Most Stones Removed

        本文链接:https://www.haomeiwen.com/subject/jhbuqqtx.html