leetcode
leetcode 851 ~ 900
移除最多的同行或同列石头

移除最多的同行或同列石头

难度:

标签:

题目描述

代码结果

运行时间: 33 ms, 内存: 16.6 MB


/*
 * 思路:
 * 使用 Java Stream API 的同样逻辑来实现并查集。
 * 我们可以使用 Arrays.stream 和 mapToObj 创建 Stone 对象的流,
 * 然后使用 Collectors.toMap 将它们按索引进行收集,
 * 最后使用同样的并查集算法来计算可移除的石头数量。
 */

import java.util.*;
import java.util.stream.*;

class Solution {
    public int removeStones(int[][] stones) {
        Map<Integer, int[]> stoneMap = IntStream.range(0, stones.length)
            .boxed()
            .collect(Collectors.toMap(i -> i, i -> stones[i]));
        UnionFind uf = new UnionFind(stones.length);
        stoneMap.forEach((i, stone1) -> {
            stoneMap.forEach((j, stone2) -> {
                if (i < j && (stone1[0] == stone2[0] || stone1[1] == stone2[1])) {
                    uf.union(i, j);
                }
            });
        });
        return stones.length - uf.getCount();
    }

    class UnionFind {
        private int[] parent;
        private int count;

        public UnionFind(int n) {
            parent = new int[n];
            count = n;
            IntStream.range(0, n).forEach(i -> parent[i] = i);
        }

        public int find(int x) {
            if (parent[x] != x) {
                parent[x] = find(parent[x]);
            }
            return parent[x];
        }

        public void union(int x, int y) {
            int rootX = find(x);
            int rootY = find(y);
            if (rootX != rootY) {
                parent[rootX] = rootY;
                count--;
            }
        }

        public int getCount() {
            return count;
        }
    }
}

解释

方法:

这道题目可以通过并查集的数据结构来解决。每块石头可以通过其行和列来进行连接,如果两块石头处于同一行或同一列,它们可以属于同一个连通分量。并查集可以帮助我们维护这些连通分量的信息。具体步骤如下:1. 初始化并查集。2. 遍历每块石头,将其行和列视为连接点,如果当前行或列已经有石头,就将当前石头与之前的石头进行合并。3. 最后,连通分量的数量即为不能被移除的石头数量,其余的石头都可以被移除。

时间复杂度:

O(n \alpha(n))

空间复杂度:

O(n)

代码细节讲解

🦆
在并查集中,为什么将行和列的索引作为连接点,而不是直接使用石头的索引?
在这个问题中,我们的目标是找出最大数量的石头,这些石头处于同一行或同一列。因此,将行和列作为连接点,可以更直观地表示石头之间的连接关系(即处于同一行或列的石头属于同一个连通分量)。如果我们直接使用石头的索引,就无法直接表达行和列之间的这种关系,处理起来也更加复杂。通过将行和列作为连接点,我们可以轻松地将处于同一行或列的石头归为一组,从而便于使用并查集算法处理。
🦆
并查集初始化时,为什么要设置p的长度为n+1而不是n?
在提供的代码中,p的长度设置为n+1是为了方便从1开始索引,避免对0的特殊处理。在Python中,列表索引通常从0开始,但在算法中从1开始索引可以使代码更简洁,特别是当涉及到数学或逻辑关系的转化时。此外,这样做能保证索引不会越界,而且更符合某些编程场景的传统习惯。
🦆
在遍历stones时,为什么要从索引1开始而不是0?这对并查集的操作有什么影响吗?
在遍历stones时从索引1开始是为了匹配并查集中使用的从1开始的索引系统。这样做主要是为了代码的一致性和简洁性,避免在并查集操作中出现将0作为有效节点的混淆。在并查集的实现中,通常预期所有的索引都是有效的,从1开始可以确保0不会被误用,因为在某些场合0可能被作为特殊值或哨兵值。
🦆
在算法最后,通过计算连通分量的数量来确定不能被移除的石头数量,这里的逻辑是如何确保每个连通分量中至少有一块石头不能被移除的?
在这个算法中,每个连通分量代表了至少一行或一列中的所有石头。题目的要求是可以移除除了一个之外的所有同行或同列的石头。因此,每个连通分量至少需要保留一个石头作为代表,以确保行或列的存在。通过统计并查集中根节点的数量(也就是连通分量的数量),我们可以确定至少需要保留的石头数量。每个连通分量中的其他石头都可以被移除,因为它们与至少一个其他石头共行或共列。

相关问题