华为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 条边都会被枚举一次)。


算法步骤

  1. 将点集放入哈希表(或集合)中,方便 O(1) 查找。

  2. 遍历所有点对 (p1, p2),计算 dx = x2 - x1, dy = y2 - y1

  3. 对每个点对,用上述两种旋转方式计算 p3p4

  4. 如果 p3p4 都在点集中,则找到一个正方形。

  5. 最终计数除以 4,返回结果。


代码实现

Python 实现

python

复制代码
def count_squares(points):
    point_set = set((x, y) for x, y in points)
    n = len(points)
    count = 0
    for i in range(n):
        x1, y1 = points[i]
        for j in range(i + 1, n):
            x2, y2 = points[j]
            dx = x2 - x1
            dy = y2 - y1
            # 情况1
            x3 = x1 - dy
            y3 = y1 + dx
            x4 = x2 - dy
            y4 = y2 + dx
            if (x3, y3) in point_set and (x4, y4) in point_set:
                count += 1
            # 情况2
            x3 = x1 + dy
            y3 = y1 - dx
            x4 = x2 + dy
            y4 = y2 - dx
            if (x3, y3) in point_set and (x4, y4) in point_set:
                count += 1
    return count // 4

if __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;
            // 情况1
            int x3 = x1 - dy, y3 = y1 + dx;
            int x4 = x2 - dy, y4 = y2 + dx;
            if (pointSet.count({x3, y3}) && pointSet.count({x4, y4})) {
                count++;
            }
            // 情况2
            x3 = 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; // 输出 2
    return 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;
                // 情况1
                int x3 = x1 - dy, y3 = y1 + dx;
                int x4 = x2 - dy, y4 = y2 + dx;
                if (pointSet.contains(x3 + "," + y3) && pointSet.contains(x4 + "," + y4)) {
                    count++;
                }
                // 情况2
                x3 = 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;
            // 情况1
            let x3 = x1 - dy, y3 = y1 + dx;
            let x4 = x2 - dy, y4 = y2 + dx;
            if (pointSet.has(`${x3},${y3}`) && pointSet.has(`${x4},${y4}`)) {
                count++;
            }
            // 情况2
            x3 = 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)); // 输出 2

Go 实现

go

复制代码
package main

import "fmt"

func countSquares(points [][2]int) int {
    pointSet := make(map[[2]int]bool)
    for _, p := range points {
        pointSet[p] = true
    }
    n := len(points)
    count := 0
    for 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 - x1
            dy := y2 - y1
            // 情况1
            x3, y3 := x1-dy, y1+dx
            x4, y4 := x2-dy, y2+dx
            if pointSet[[2]int{x3, y3}] && pointSet[[2]int{x4, y4}] {
                count++
            }
            // 情况2
            x3, y3 = x1+dy, y1-dx
            x4, y4 = x2+dy, y2-dx
            if 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 避免重复计数。

相关推荐
_深海凉_2 小时前
LeetCode热题100-颜色分类
python·算法·leetcode
cmpxr_2 小时前
【C】局部变量和全局变量及同名情况
c语言·开发语言
AC赳赳老秦2 小时前
OpenClaw email技能:批量发送邮件、自动回复,高效处理工作邮件
运维·人工智能·python·django·自动化·deepseek·openclaw
zhaoshuzhaoshu3 小时前
Python 语法之数据结构详细解析
python
AI问答工程师3 小时前
Meta Muse Spark 的"思维压缩"到底是什么?我用 Python 复现了核心思路(附代码)
人工智能·python
zfan5204 小时前
python对Excel数据处理(1)
python·excel·pandas
小饕4 小时前
我从零搭建 RAG 学到的 10 件事
python
老歌老听老掉牙4 小时前
PyQt5+Qt Designer实战:可视化设计智能参数配置界面,告别手动布局时代!
python·qt
网域小星球4 小时前
C 语言从 0 入门(十七)|结构体指针 + 动态内存 + 文件综合实战
c语言·开发语言·文件操作·结构体指针·动态内存·综合项目
格鸰爱童话5 小时前
向AI学习项目技能(六)
java·人工智能·spring boot·python·学习