华为OD机考:计算正方形数量(Python C/C++ JAVA JS GO)
题目理解
题意
在平面直角坐标系中,给定一组坐标点(整数坐标),求这些点可以构成多少个正方形。
注意:正方形可能有任意朝向,不一定是边平行于坐标轴的正方形。
思路分析
已知两个点,可以推算出另外两个点,从而判断它们是否在给定的点集中。
几何原理:
假设已知正方形的一条边 (x1, y1) 和 (x2, y2),我们可以根据向量旋转 90° 来得到另外两个点。
设向量 dx = x2 - x1, dy = y2 - y1。
情况 1:
另外两个点:
text
x3 = x1 - dy, y3 = y1 + dx x4 = x2 - dy, y4 = y2 + dx
情况 2:
另外两个点:
text
x3 = x1 + dy, y3 = y1 - dx x4 = x2 + dy, y4 = y2 - dx
这样,对于每一对点,我们尝试把它当作正方形的一条边,检查另外两个点是否存在。
为了避免重复计数,我们最后将结果除以 4(因为每个正方形的 4 条边都会被枚举一次)。
算法步骤
将点集放入哈希表(或集合)中,方便 O(1) 查找。
遍历所有点对
(p1, p2),计算dx = x2 - x1,dy = y2 - y1。对每个点对,用上述两种旋转方式计算
p3和p4。如果
p3和p4都在点集中,则找到一个正方形。最终计数除以 4,返回结果。
代码实现
Python 实现
python
def count_squares(points):point_set = set((x, y) for x, y in points)n = len(points)count = 0for i in range(n):x1, y1 = points[i]for j in range(i + 1, n):x2, y2 = points[j]dx = x2 - x1dy = y2 - y1# 情况1x3 = x1 - dyy3 = y1 + dxx4 = x2 - dyy4 = y2 + dxif (x3, y3) in point_set and (x4, y4) in point_set:count += 1# 情况2x3 = x1 + dyy3 = y1 - dxx4 = x2 + dyy4 = y2 - dxif (x3, y3) in point_set and (x4, y4) in point_set:count += 1return count // 4if __name__ == "__main__":# 示例points = [(0,0), (1,0), (0,1), (1,1), (2,0), (2,1)]print(count_squares(points)) # 输出 2
C++ 实现
cpp
#include <iostream>
#include <vector>
#include <unordered_set>
#include <utility>using namespace std;struct PairHash {template <typename T1, typename T2>size_t operator()(const pair<T1, T2>& p) const {auto h1 = hash<T1>{}(p.first);auto h2 = hash<T2>{}(p.second);return h1 ^ (h2 << 1);
rd.xjyl.gov.cn/upload/1982074936951799808.html
rd.xjyl.gov.cn/upload/1982074936976965632.html
rd.xjyl.gov.cn/upload/1982074937044074496.html
rd.xjyl.gov.cn/upload/1982074937161515008.html
rd.xjyl.gov.cn/upload/1982074937169903616.html
rd.xjyl.gov.cn/upload/1982074937434144768.html
rd.xjyl.gov.cn/upload/1982074937585139712.html
rd.xjyl.gov.cn/upload/1982074937589334016.html
rd.xjyl.gov.cn/upload/1982074937601916928.html
rd.xjyl.gov.cn/upload/1982074937589334017.html
rd.xjyl.gov.cn/upload/1982074937685803008.html
rd.xjyl.gov.cn/upload/1982074937702580224.html
rd.xjyl.gov.cn/upload/1982074937782272000.html
rd.xjyl.gov.cn/upload/1982074937832603648.html
rd.xjyl.gov.cn/upload/1982074938067484672.html
rd.xjyl.gov.cn/upload/1982074938113622016.html
rd.xjyl.gov.cn/upload/1982074938147176448.html
rd.xjyl.gov.cn/upload/1982074938277199872.html
rd.xjyl.gov.cn/upload/1982074938382057472.html
rd.xjyl.gov.cn/upload/1982074938491109376.html
rd.xjyl.gov.cn/upload/1982074938616938496.html
rd.xjyl.gov.cn/upload/1982074938767933440.html
rd.xjyl.gov.cn/upload/1982074938801487872.html}
};int countSquares(vector<pair<int, int>>& points) {unordered_set<pair<int, int>, PairHash> pointSet;for (auto& p : points) {pointSet.insert(p);}int n = points.size();int count = 0;for (int i = 0; i < n; i++) {int x1 = points[i].first, y1 = points[i].second;for (int j = i + 1; j < n; j++) {int x2 = points[j].first, y2 = points[j].second;int dx = x2 - x1;int dy = y2 - y1;// 情况1int x3 = x1 - dy, y3 = y1 + dx;int x4 = x2 - dy, y4 = y2 + dx;if (pointSet.count({x3, y3}) && pointSet.count({x4, y4})) {count++;}// 情况2x3 = x1 + dy, y3 = y1 - dx;x4 = x2 + dy, y4 = y2 - dx;if (pointSet.count({x3, y3}) && pointSet.count({x4, y4})) {count++;}}}return count / 4;
}int main() {vector<pair<int, int>> points = {{0,0}, {1,0}, {0,1}, {1,1}, {2,0}, {2,1}};cout << countSquares(points) << endl; // 输出 2return 0;
}Java 实现
java
import java.util.*;public class Main {public static int countSquares(int[][] points) {Set<String> pointSet = new HashSet<>();for (int[] p : points) {pointSet.add(p[0] + "," + p[1]);}int n = points.length;int count = 0;for (int i = 0; i < n; i++) {int x1 = points[i][0], y1 = points[i][1];for (int j = i + 1; j < n; j++) {int x2 = points[j][0], y2 = points[j][1];int dx = x2 - x1;int dy = y2 - y1;// 情况1int x3 = x1 - dy, y3 = y1 + dx;int x4 = x2 - dy, y4 = y2 + dx;if (pointSet.contains(x3 + "," + y3) && pointSet.contains(x4 + "," + y4)) {count++;}// 情况2x3 = x1 + dy; y3 = y1 - dx;x4 = x2 + dy; y4 = y2 - dx;if (pointSet.contains(x3 + "," + y3) && pointSet.contains(x4 + "," + y4)) {count++;}}}return count / 4;}public static void main(String[] args) {int[][] points = {{0,0}, {1,0}, {0,1}, {1,1}, {2,0}, {2,1}};System.out.println(countSquares(points)); // 输出 2}
}JavaScript 实现
javascript
function countSquares(points) {const pointSet = new Set();for (const [x, y] of points) {pointSet.add(`${x},${y}`);
rd.xjyl.gov.cn/upload/1982074939057340416.html
rd.xjyl.gov.cn/upload/1982074939065729024.html
rd.xjyl.gov.cn/upload/1982074939132837888.html
rd.xjyl.gov.cn/upload/1982074939149615104.html
rd.xjyl.gov.cn/upload/1982074939158003712.html
rd.xjyl.gov.cn/upload/1982074939183169536.html
rd.xjyl.gov.cn/upload/1982074939212529664.html
rd.xjyl.gov.cn/upload/1982074939275444225.html
rd.xjyl.gov.cn/upload/1982074939275444224.html
rd.xjyl.gov.cn/upload/1982074939434827776.html
rd.xjyl.gov.cn/upload/1982074939459993600.html
rd.xjyl.gov.cn/upload/1982074939569045504.html
rd.xjyl.gov.cn/upload/1982074939724234752.html
rd.xjyl.gov.cn/upload/1982074939778760704.html
rd.xjyl.gov.cn/upload/1982074939837480960.html
rd.xjyl.gov.cn/upload/1982074939933949952.html
rd.xjyl.gov.cn/upload/1982074939946532864.html
rd.xjyl.gov.cn/upload/1982074940097527808.html
rd.xjyl.gov.cn/upload/1982074940156248064.html
rd.xjyl.gov.cn/upload/1982074940269494272.html
rd.xjyl.gov.cn/upload/1982074940399517696.html
rd.xjyl.gov.cn/upload/1982074940445655040.html
rd.xjyl.gov.cn/upload/1982074940508569600.html
rd.xjyl.gov.cn/upload/1982074940730867712.html
rd.xjyl.gov.cn/upload/1982074940781199360.html
rd.xjyl.gov.cn/upload/1982074940831531008.html
rd.xjyl.gov.cn/upload/1982074940877668352.html
rd.xjyl.gov.cn/upload/1982074940907028480.html
rd.xjyl.gov.cn/upload/1982074940911222784.html}const n = points.length;let count = 0;for (let i = 0; i < n; i++) {const [x1, y1] = points[i];for (let j = i + 1; j < n; j++) {const [x2, y2] = points[j];const dx = x2 - x1;const dy = y2 - y1;// 情况1let x3 = x1 - dy, y3 = y1 + dx;let x4 = x2 - dy, y4 = y2 + dx;if (pointSet.has(`${x3},${y3}`) && pointSet.has(`${x4},${y4}`)) {count++;}// 情况2x3 = x1 + dy, y3 = y1 - dx;x4 = x2 + dy, y4 = y2 - dx;if (pointSet.has(`${x3},${y3}`) && pointSet.has(`${x4},${y4}`)) {count++;}}}return count / 4;
}// 示例
const points = [[0,0], [1,0], [0,1], [1,1], [2,0], [2,1]];
console.log(countSquares(points)); // 输出 2Go 实现
go
package mainimport "fmt"func countSquares(points [][2]int) int {pointSet := make(map[[2]int]bool)for _, p := range points {pointSet[p] = true}n := len(points)count := 0for i := 0; i < n; i++ {x1, y1 := points[i][0], points[i][1]for j := i + 1; j < n; j++ {x2, y2 := points[j][0], points[j][1]dx := x2 - x1dy := y2 - y1// 情况1x3, y3 := x1-dy, y1+dxx4, y4 := x2-dy, y2+dxif pointSet[[2]int{x3, y3}] && pointSet[[2]int{x4, y4}] {count++}// 情况2x3, y3 = x1+dy, y1-dxx4, y4 = x2+dy, y2-dxif pointSet[[2]int{x3, y3}] && pointSet[[2]int{x4, y4}] {count++}}}return count / 4
}func main() {points := [][2]int{{0, 0}, {1, 0}, {0, 1}, {1, 1}, {2, 0}, {2, 1}}fmt.Println(countSquares(points)) // 输出 2
}复杂度分析
时间复杂度:O(n²),其中 n 是点的数量。
空间复杂度:O(n),用于存储点集哈希表。
总结
这个方法利用了正方形的几何性质,通过枚举两个点并推导出可能的另外两个点,用哈希集合快速判断是否存在,从而统计正方形数量。最后除以 4 避免重复计数。
