华为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 避免重复计数。

相关推荐
傻童:CPU3 小时前
C语言需要掌握的基础知识点之DFS(深度优先搜索)
c语言·1024程序员节
我是华为OD~HR~栗栗呀3 小时前
华为od-22届考研-C++面经
java·前端·c++·python·华为od·华为·面试
我是华为OD~HR~栗栗呀3 小时前
华为OD, 测试面经
java·c++·python·华为od·华为·面试
Yupureki5 小时前
从零开始的C++学习生活 12:AVL树全面解析
c语言·数据结构·c++·学习·visual studio
czy87874755 小时前
用C语言实现组合模式
c语言·组合模式
我是华为OD~HR~栗栗呀5 小时前
华为OD-23届-测试面经
java·前端·c++·python·华为od·华为·面试
我是华为OD~HR~栗栗呀5 小时前
华为od面经-23届-Java面经
java·c语言·c++·python·华为od·华为·面试
逐步前行8 小时前
C标准库--C99--布尔型<stdbool.h>
c语言·开发语言
程序员爱钓鱼8 小时前
Python编程实战 · 基础入门篇 | 元组(tuple)
后端·python·ipython