题解:有效的正方形
题目分析
题目描述
给定二维空间中四个点的坐标 p1, p2, p3, p4(坐标无固定顺序),判断这四个点能否构成一个有效的正方形。有效正方形需满足核心条件:四条边长度相等,四个内角均为90度直角。
核心难点
- 输入的四个点无固定顺序,无法直接按"边的顺序"判断;
- 直接计算两点间距离会引入浮点数精度误差(如√2是无理数,开平方后无法精确表示);
- 需排除特殊无效情况(如四点重合、三点共线、仅三条边相等但对角线不满足直角条件等)。
关键数学性质(正方形的充要条件)
对于无顺序的四个点,若能构成正方形,则其所有两两组合的距离(共 C(4,2)=6 组)满足:
- 最小距离不为0(排除重合点);
- 6个距离中仅包含两种数值:
- 较小值(边长)出现4次(对应正方形的四条边);
- 较大值(对角线)出现2次(对应正方形的两条对角线);
- 对角线长度的平方 = 2 × 边长长度的平方(由勾股定理推导,直角三角形斜边平方等于两直角边平方和)。
解题思路
基于上述数学性质,核心思路是用距离平方替代实际距离(规避浮点数精度误差),通过统计6组两两距离平方的特征完成判断:
- 定义辅助函数,计算两点间距离的平方(避免开平方操作);
- 遍历四个点的所有两两组合,计算6组距离平方并存储;
- 对距离平方数组排序,便于快速验证特征:
- 排序后前4个元素为"边长平方",后2个为"对角线平方";
- 验证核心条件:最小距离平方≠0、前4个值相等、后2个值相等、对角线平方=2×边长平方。
代码实现(带详细注释)
cpp
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
// 辅助函数:计算两点间距离的平方(避免浮点数精度误差)
long long get_distance(vector<int>& p1, vector<int>& p2) {
// 用long long避免int溢出(坐标差值的平方可能超出int范围)
long long dx = p1[0] - p2[0]; // x轴坐标差值
long long dy = p1[1] - p2[1]; // y轴坐标差值
return dx * dx + dy * dy; // 距离平方公式:(x1-x2)² + (y1-y2)²
}
bool validSquare(vector<int>& p1, vector<int>& p2, vector<int>& p3, vector<int>& p4) {
// 将四个点存入数组,方便遍历所有两两组合
vector<vector<int>> points = {p1, p2, p3, p4};
// 存储6组两两距离的平方
vector<long long> distance_squares;
// 遍历所有两两组合(i<j避免重复计算),共C(4,2)=6组
for (int i = 0; i < 4; ++i) {
for (int j = i + 1; j < 4; ++j) {
distance_squares.push_back(get_distance(points[i], points[j]));
}
}
// 排序后:前4个为边长平方,后2个为对角线平方
sort(distance_squares.begin(), distance_squares.end());
// 核心判断逻辑:逐一验证正方形的数学特征
return distance_squares[0] != 0 // 条件1:无重合点(最小距离不为0)
&& distance_squares[0] == distance_squares[1] // 条件2:前4个边长平方相等
&& distance_squares[1] == distance_squares[2]
&& distance_squares[2] == distance_squares[3]
&& distance_squares[4] == distance_squares[5] // 条件3:两个对角线平方相等
&& 2 * distance_squares[0] == distance_squares[4]; // 条件4:对角线平方=2×边长平方
}
};
代码关键解释
-
辅助函数
get_distance:- 核心作用:计算两点间距离的平方,彻底避免开平方操作带来的浮点数精度问题;
- 数据类型选择:使用
long long而非int,防止坐标差值较大时(如差值为1e4),平方运算超出int的取值范围导致溢出。
-
遍历两两组合:
- 采用
i < j的双层循环,确保每个点对只计算一次,最终得到6组距离平方(对应4个点的所有两两组合),无重复、无遗漏。
- 采用
-
排序与条件判断:
- 排序后数组的前4个元素对应正方形四条边的平方,后2个对应两条对角线的平方,通过连续的相等判断可快速验证"四边相等、对角线相等";
- 最后验证"对角线平方=2×边长平方",确保四个角为90度,排除"菱形(四边相等但非直角)"的无效情况。
复杂度分析
-
时间复杂度 :O(1)。
四个点的两两组合固定为6组,计算距离平方的操作是常数级;排序6个元素的时间复杂度为常数(排序固定数量的元素无渐近复杂度),因此整体时间复杂度为O(1)。
-
空间复杂度 :O(1)。
仅使用固定大小的数组存储4个点和6个距离平方,无动态扩容的空间开销,空间复杂度为常数级。
测试用例验证
| 输入点坐标 | 输出 | 说明 |
|---|---|---|
| [0,0],[1,1],[1,0],[0,1] | true | 标准正方形 |
| [0,0],[0,0],[0,0],[0,0] | false | 四点重合 |
| [0,0],[1,2],[3,1],[2,-1] | false | 菱形(边长相等但非直角) |
| [1,0],[-1,0],[0,1],[0,-1] | true | 以原点为中心的正方形 |
总结
- 核心技巧:用距离平方替代实际距离,彻底规避浮点数精度误差,是解决几何距离判定问题的常用手段;
- 判定逻辑:通过排序后统计距离平方的分布特征,精准匹配正方形的数学性质,覆盖所有边界情况;
- 算法优势:时间/空间复杂度均为常数级,逻辑简洁、执行高效,是该问题的最优解法。