Problem: 3025. 人员站位的方案数 I
文章目录
- 整体思路
- 完整代码
- 时空复杂度
- 时间复杂度:O(N^3)
- 空间复杂度:O(1)
整体思路
这段代码旨在解决一个几何计数问题:给定平面上的 n
个点,计算满足特定条件的“点对” (i, j)
的数量。
根据代码的逻辑,一个点对 (i, j)
被认为是一个有效的“对子”,必须满足以下两个条件:
- 位置关系:点
i
必须位于点j
的左上方区域。代码中的if ((xa < xb && ya > yb) || (xa < xb && ya == yb) || (ya > yb && xa == xb))
定义了这个关系,即xa <= xb
且ya >= yb
,并且(xa, ya)
不能等于(xb, yb)
。 - “空”矩形条件:由点
i
和点j
作为对角顶点构成的矩形区域内(包括边界),不能包含任何其他的点k
。这个矩形区域由xa <= x <= xb
和yb <= y <= ya
定义。
该算法采用了一种 暴力枚举 (Brute-force Enumeration) 的方法来找到所有满足条件的点对。
其核心逻辑步骤如下:
-
外层双重循环:枚举所有可能的点对
- 代码使用两层嵌套的
for
循环来遍历所有可能的点对(i, j)
。 if (j == i)
这个判断会跳过一个点与自身构成点对的情况。- 这确保了算法会检查
n * (n-1)
个有序点对。
- 代码使用两层嵌套的
-
检查位置关系
- 对于每一个点对
(i, j)
,代码首先检查它们是否满足xa <= xb
且ya >= yb
的位置关系。如果这个基本条件都不满足,那么这个点对肯定不是有效的,直接跳过,继续检查下一个点对。
- 对于每一个点对
-
内层循环:检查“空”矩形条件
- 如果位置关系满足,算法就进入了最关键的验证步骤。
- 它启动了第三层嵌套的
for
循环,遍历所有其他的点k
(即k != i
且k != j
)。 - 对于每一个点
k
,它会检查其坐标(xc, yc)
是否落在了由点i
和点j
定义的矩形区域内,即xa <= xc && xc <= xb && ya >= yc && yc >= yb
。 - 标志位
valid
:- 在检查开始前,
valid
被初始化为 1,假设这个矩形是“空”的。 - 一旦在矩形内发现任何一个点
k
,就说明“空”矩形条件被违反了。此时,立即将valid
设为 0,并用break
提前跳出内层循环,因为没有必要再检查其他的点k
了。
- 在检查开始前,
- 当内层循环结束后,如果
valid
仍然为 1,就说明矩形内确实没有任何其他点。
-
累加结果
- 如果一个点对
(i, j)
同时满足了位置关系和“空”矩形条件(即valid == 1
),那么就将计数器ans
加一。
- 如果一个点对
-
返回结果
- 在检查完所有可能的点对后,
ans
中就存储了最终的总数,将其返回。
- 在检查完所有可能的点对后,
完整代码
class Solution {/*** 计算满足特定条件的点对数量。* 条件:点i在点j的左上区域,且以i,j为对角顶点的矩形内没有其他点。* @param points 一个二维数组,每个子数组 [x, y] 代表一个点的坐标。* @return 符合条件的点对的数量。*/public int numberOfPairs(int[][] points) {int n = points.length;int ans = 0;// 步骤 1: 枚举所有可能的点对 (i, j)for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {// 一个点不能与自身配对if (j == i) {continue;}int xa = points[i][0];int ya = points[i][1];int xb = points[j][0];int yb = points[j][1];// 步骤 2: 检查位置关系,点 i 是否在点 j 的左上区域 (xa <= xb, ya >= yb)if (xa <= xb && ya >= yb) {// 假设当前点对是有效的,即矩形是“空”的int valid = 1;// 步骤 3: 检查“空”矩形条件// 遍历所有其他点 kfor (int k = 0; k < n; k++) {// 跳过点 i 和点 j 本身if (k == i || k == j) {continue;}int xc = points[k][0];int yc = points[k][1];// 检查点 k 是否在由 i 和 j 定义的矩形区域内if (xa <= xc && xc <= xb && ya >= yc && yc >= yb) {// 如果找到了一个点在矩形内,则此点对 (i, j) 无效valid = 0;break; // 无需再检查其他点 k,提前退出内层循环}}// 步骤 4: 如果检查完所有点k后,矩形仍然是“空”的,则累加结果ans += valid;}}}return ans;}
}
时空复杂度
时间复杂度:O(N^3)
- 外层循环:
for (int i = 0; i < n; i++)
执行N
次。 - 中层循环:
for (int j = 0; j < n; j++)
执行N
次。- 这两层循环构成了对所有
N*N
个有序点对的枚举。
- 这两层循环构成了对所有
- 内层循环:
for (int k = 0; k < n; k++)
执行N
次。- 这个循环用于检查矩形区域。
- 综合分析:
- 算法的结构是三层嵌套的循环,每一层的循环次数都与
N
相关。 - 在最坏的情况下(例如,所有点对都满足位置关系),内层循环几乎总是会被执行。
- 因此,总的操作次数大致是
N * N * N
。 - 所以,该算法的时间复杂度是 O(N^3)。
- 算法的结构是三层嵌套的循环,每一层的循环次数都与
空间复杂度:O(1)
- 主要存储开销:算法在执行过程中没有创建任何与输入规模
N
成比例的新的数据结构。 - 辅助变量:只使用了
n
,ans
,i
,j
,k
和几个用于存储坐标的int
变量。这些变量的数量是固定的,不随输入points
数组中点的数量N
的增加而增加。
综合分析:
算法所需的额外辅助空间是常数级别的。因此,其空间复杂度为 O(1)。