青训营-可以移除的石头问题

71 阅读2分钟

问题描述

在一个二维平面上有若干块石头,每块石头位于某个整数坐标点上。每个坐标点上最多只能有一块石头。如果一块石头的同一行或同一列上存在其他石头,那么可以移除这块石头。

给定一个长度为 n 的数组 stones,其中 stones[i] = [xi, yi] 表示第 i 块石头的坐标。你的任务是计算可以移除的石头的最大数量。


测试样例

样例1:

输入:stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2],[3,3],[2,3]]
输出:7

样例2:

输入:stones = [[0,0]]
输出:0

样例3:

输入:stones = [[0,1],[1,0],[1,1]]
输出:2

解题思路

  1. 连通分量:我们可以将所有在同一行或同一列上的石头看作一个连通分量。每个连通分量中的石头都可以通过某种顺序移除,直到只剩下一个石头。
  2. 并查集:为了高效地找到这些连通分量,我们可以使用并查集(Union-Find)数据结构。并查集可以帮助我们快速合并和查找连通分量。
  3. 计算移除的石头数量:对于每个连通分量,我们可以移除其中的所有石头,除了最后一个。因此,移除的石头数量就是总石头数减去连通分量的数量。

算法步骤

  1. 初始化并查集:为每个石头创建一个并查集节点。
  2. 合并连通分量:遍历所有石头,如果两个石头在同一行或同一列,则将它们合并到同一个连通分量中。
  3. 计算结果:统计连通分量的数量,然后用总石头数减去连通分量的数量,得到可以移除的石头数量。

数据结构选择

  • 并查集:用于高效地合并和查找连通分量。

Java代码

import java.util.HashMap;
import java.util.Map;
public class Main {
  private int[] parent;
  private int count;
public int solution(int[][] stones) {
    int n = stones.length;
    // 初始化并查集
    count = n;
    parent = new int[n];
    for (int i = 0; i < n; i++) {
        parent[i] = i;
    }

    // 使用Map来存储行和列的索引
    Map<Integer, Integer> rowMap = new HashMap<>();
    Map<Integer, Integer> colMap = new HashMap<>();

    for (int i = 0; i < n; i++) {
        int x = stones[i][0], y = stones[i][1];
        // 合并同一行的石头
        int finalI = i;
        union(i, rowMap.computeIfAbsent(x, k -> finalI));
        // 合并同一列的石头
        int finalI1 = i;
        union(i, colMap.computeIfAbsent(y, k -> finalI1));
    }

    // 最终的连通分量数量
    return n - count;
}

private int find(int p) {
    while (p != parent[p]) {
        // 路径压缩
        parent[p] = parent[parent[p]];
        p = parent[p];
    }
    return p;
}

private void union(int p, int q) {
    int rootP = find(p);
    int rootQ = find(q);
    if (rootP == rootQ) {
        return;
    }
    parent[rootP] = rootQ;
    count--; // 减少一个连通分量
}

public static void main(String[] args) {
    Main main = new Main();
    System.out.println(main.solution(new int[][]{{0, 0}, {0, 1}, {1, 0}, {1, 2}, {2, 1}, {2, 2}, {3, 3}, {2, 3}})); // 输出:7
    System.out.println(main.solution(new int[][]{{0, 0}})); // 输出:0
    System.out.println(main.solution(new int[][]{{0, 1}, {1, 0}, {1, 1}})); // 输出:2
}
}