问题描述
小M有n个点,每个点的坐标为(xi,yi)。她可以从一个点出发,平行于坐标轴移动,直到到达另一个点。具体来说,她可以从 (x1,y1) 直接到达 (x2,y1) 或者 (x1,y2),但无法直接到达 (x2,y2)。为了使得任意两个点之间可以互相到达,小M可以选择增加若干个新的点。
你的任务是计算最少需要增加多少个点,才能保证任意两个点之间可以通过平行于坐标轴的路径互相到达。
测试样例
样例1:
输入:
n = 2, points = [[1, 1], [2, 2]]
输出:1
样例2:
输入:
n = 3, points = [[1, 2], [2, 3], [4, 1]]
输出:2
样例3:
输入:
n = 4, points = [[3, 4], [5, 6], [3, 6], [5, 4]]
输出:0
要解决这个问题,我们需要通过分析点之间的连接性,最小化新增点的数量,确保所有点能够通过平行于坐标轴的路径互相到达。这是一道与图连通性相关的几何问题。
以下为解题思路
解题思路
-
点的连接规则:
- 两点可以互相到达的条件是它们在同一行 (x1=x2x_1 = x_2) 或同一列 (y1=y2y_1 = y_2)。换句话说,我们需要把这些点划分为同一行或同一列的连通块。
-
连通块的定义:
- 任意两点属于同一个连通块,当且仅当它们之间通过一系列满足上述条件的点可以连通。
- 每个连通块内的点可以直接或间接互相到达。
-
目标:
- 计算连通块的数量 kk。
- 我们需要保证所有点属于同一个连通块,因此至少需要新增 k−1k - 1 个点。
-
算法设计:
-
将问题建模为一个图问题,其中每个点是一个节点:
- 如果两点 (x1,y1)(x_1, y_1) 和 (x2,y2)(x_2, y_2) 满足 x1=x2x_1 = x_2 或 y1=y2y_1 = y_2,它们之间有一条边。
-
使用并查集或深度优先搜索 (DFS) 找到所有连通块。
-
结果是连通块的数量减去 1,即 k−1k - 1。
-
-
实现方式:
-
利用并查集(Union-Find)高效地处理连通性问题。
-
构建虚拟节点以减少复杂度:
- 对于每个 xix_i 和 yiy_i,将点的 xx-坐标和 yy-坐标分开存储,并将其归类到同一连通块。
-
算法实现
以下是基于并查集的实现:
class UnionFind:
def __init__(self):
self.parent = {}
def find(self, x):
if x not in self.parent:
self.parent[x] = x
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, x, y):
root_x = self.find(x)
root_y = self.find(y)
if root_x != root_y:
self.parent[root_x] = root_y
def min_additional_points(n, points):
uf = UnionFind()
# 建立点的连通性:按 x 和 y 坐标分别分类
for x, y in points:
# 将点的 x 坐标和 y 坐标虚拟为节点,并归并
uf.union(f"x_{x}", f"y_{y}")
# 查找所有独立的连通块
connected_components = set()
for x, y in points:
connected_components.add(uf.find(f"x_{x}"))
connected_components.add(uf.find(f"y_{y}"))
# 连通块的数量
num_connected_components = len(connected_components)
return num_connected_components - 1
测试用例
样例 1:
输入:
n = 2
points = [[1, 1], [2, 2]]
print(min_additional_points(n, points)) # 输出:1
样例 2:
输入:
n = 3
points = [[1, 2], [2, 3], [4, 1]]
print(min_additional_points(n, points)) # 输出:2
样例 3:
输入:
n = 4
points = [[3, 4], [5, 6], [3, 6], [5, 4]]
print(min_additional_points(n, points)) # 输出:0
复杂度分析
-
时间复杂度:
- 构建并查集和执行 unionunion 操作:O(n⋅α(n))O(n \cdot \alpha(n)),其中 α(n)\alpha(n) 是反阿克曼函数的复杂度,几乎是常数。
- 遍历所有点和计算连通块:O(n)O(n)。
- 总复杂度:O(n)O(n)。
-
空间复杂度:
- 并查集的存储消耗:O(n)O(n),存储所有虚拟节点。
关键点总结
- 使用并查集解决坐标平面上的连通性问题。
- 虚拟节点将 xx-坐标和 yy-坐标统一建模为连通性问题。
- 输出结果为 连通块数量−1\text{连通块数量} - 1,对应最少新增点的数量。