149. 小A的移动点 解析 | 豆包MarsCode AI刷题

50 阅读3分钟

题目大意

给定平面直角坐标系中若干个点,如果两个点的横坐标或纵坐标相同则认为它们是连通的,问现在至少需要添加几个点才能使所有点之间都连通。

测试样例及解释

样例1:

输入:n = 2, points = [[1, 1], [2, 2]]
输出:1

可以在 (1,2)(1,2) 或者 (2,1)(2,1) 添加一个点使这两个点连通。

样例2:

输入:n = 3, points = [[1, 2], [2, 3], [4, 1]]
输出:2

可以在 (1,1)(1,1)(1,3)(1,3) 各添加一个点使这三个点连通。

样例3:

输入:n = 4, points = [[3, 4], [5, 6], [3, 6], [5, 4]]
输出:0

这四个点组成一个矩形,已经互相连通,因此不需要再添加新的点。

解题思路

很明显,这种与连通性相关的问题可以使用并查集来解决。我们可以将所有横坐标相同的点合并到同一个集合中,所有纵坐标相同的点也合并到同一个集合中。但是我们需要考虑如何将一个十字形的结构准确无误的合并到同一个集合中。如果一个点的横坐标存在一个集合,纵坐标也存在一个集合,我们就不能简单的将这个点同时放入其横坐标所在的集合与其纵坐标所在的集合,而应该将它们合并为同一个集合。因此,我们可以设计这样的步骤:

  1. 检查当前点的横坐标是否存在一个集合,如果不存在则记录当前点的横坐标对应的集合的代表元为自己;否则找到该集合的代表元,并将代表元的并查集数组修改为当前点,或者说将当前点设置为代表元;

  2. 检查当前点的纵坐标是否存在一个集合,如果不存在则记录当前点的纵坐标对应的集合的代表元为自己;否则找到该集合的代表元,并将当前点的并查集数组修改为代表元,或者说直接将当前点加入该集合;

  3. 这样就可以规避未能将两个集合合并在一起的问题了,当然我们也可以同时将横纵坐标所在集合的代表元设置为当前点,同样可以解决这个问题(这样其实更好,还可以解决下面第 4 点说的这个问题)。然后我们就可以统计并查集数组仍然为自己的点的数量,将这个数量减一就是这道题的答案了。

  4. 如果此时我们运行这个程序,就会发现无法通过第三个测试样例,并且输出的答案变成了负数。因为此时所有的点组成了一个环,他们的并查集数组均不为自己。因此我们在进行第二步的时候需要额外进行判断,如果当前点的纵坐标对应的集合的代表元与当前点的横坐标对应的集合的代表元已经相同则不需要进行处理。