华为OD机试真题---构成正方形的数量


一、题目描述

输入N个互不相同的二维整数坐标,求这N个坐标可以构成的正方形数量。输入的第一行为N,代表坐标数量,N为正整数且N≤100。之后的N行输入为坐标xy,以空格分隔,x和y均为整数,且-10≤x, y≤10。输出可以构成的正方形数量。

二、解题思路

要解决这个问题,可以使用以下思路:

  1. 遍历所有可能的点对

    • 使用两个嵌套的循环遍历所有可能的点对(i,j),其中i和j分别代表两个点的索引。
  2. 计算正方形的其他两个顶点

    • 对于每一对点(x1,y1)和(x2,y2),可以计算出另外两个可能的正方形顶点的坐标。
      • 一种可能的计算方法是:
        • x3 = x1 - (y1 - y2)
        • y3 = y1 + (x1 - x2)
        • x4 = x2 - (y1 - y2)
        • y4 = y2 + (x1 - x2)
      • 另一种可能的计算方法是:
        • x5 = x1 + (y1 - y2)
        • y5 = y1 - (x1 - x2)
        • x6 = x2 + (y1 - y2)
        • y6 = y2 - (x1 - x2)
  3. 检查计算出的点是否在给定的点集中

    • 使用一个集合(或哈希表)来存储所有的点,以便快速查找。
    • 检查计算出的点(x3,y3)、(x4,y4)、(x5,y5)和(x6,y6)是否都在点集中。
  4. 统计正方形的数量

    • 如果四个点都在点集中,则找到了一个正方形。
    • 由于每个正方形可能被计算多次(例如,通过不同的点对计算得出),因此需要确保不重复计数。
    • 一种简单的方法是,由于每个正方形被计算了4次(通过其4条边中的任意2条边都可以确定一个正方形),所以最后的结果需要除以4。

三、代码实现


import java.util.*;

public class SquareCounter {
   /**
     * 计算由给定点集能够组成的正方形的数量
     *
     * @param points 二维数组,每个元素表示平面上的一个点,包含x和y坐标
     * @return 正方形的数量
     */
    public static int countSquares(int[][] points) {
        // 使用HashMap来存储点,以便快速查找,键为点的字符串表示
        Map<String, Boolean> pointMap = new HashMap<>();
        for (int i = 0; i < points.length; i++) {
            int x = points[i][0];
            int y = points[i][1];
            String key = x + "," + y;
            pointMap.put(key, true);
        }

        int count = 0;
        int n = points.length;

        // 枚举所有可能的点对
        for (int i = 0; i < n; i++) {
            int x1 = points[i][0];
            int y1 = points[i][1];

            for (int j = i + 1; j < n; j++) {
                int x2 = points[j][0];
                int y2 = points[j][1];

                // 计算两组可能的正方形顶点
                int x3 = x1 - (y1 - y2);
                int y3 = y1 + (x1 - x2);
                String key3 = x3 + "," + y3;

                int x4 = x2 - (y1 - y2);
                int y4 = y2 + (x1 - x2);
                String key4 = x4 + "," + y4;

                if (pointMap.containsKey(key3) && pointMap.containsKey(key4)) {
                    count++;
                }

                int x5 = x1 + (y1 - y2);
                int y5 = y1 - (x1 - x2);
                String key5 = x5 + "," + y5;

                int x6 = x2 + (y1 - y2);
                int y6 = y2 - (x1 - x2);
                String key6 = x6 + "," + y6;

                if (pointMap.containsKey(key5) && pointMap.containsKey(key6)) {
                    count++;
                }
            }
        }

        // 由于每个正方形被计算了4次(通过其4条边),所以需要除以4
        return count / 4;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取点的数量
        int n = scanner.nextInt();
        int[][] points = new int[n][2];

        // 读取点的坐标
        for (int i = 0; i < n; i++) {
            points[i][0] = scanner.nextInt();
            points[i][1] = scanner.nextInt();
        }

        // 计算并输出结果
        int result = countSquares(points);
        System.out.println(result);

        scanner.close();
    }
}

四、注意事项

  1. 输入检查:确保输入的N为正整数,且坐标值在给定范围内。
  2. 性能优化:使用集合(或哈希表)来存储和查找点,以提高性能。
  3. 避免重复计数:由于每个正方形可能被计算多次,因此需要确保不重复计数。

输入:

5
0 0
1 1
1 0
0 1
2 2

解释:

  • 输入的第一行是点的数量 n = 5
  • 接下来的五行是五个点的坐标,分别是 (0, 0), (1, 1), (1, 0), (0, 1), 和 (2, 2)

预期输出:

1

这表示在给定的点集中,可以构成一个正方形。

解释:

  • 这五个点可以构成一个正方形,其顶点为 (0, 0), (1, 0), (1, 1), 和 (0, 1)
  • 注意,虽然 (2, 2) 点也在输入中,但它并不参与构成这个正方形。
  • 由于每个正方形在这个算法中会被其四条边分别计算一次,所以最终的结果需要除以4。但在这个例子中,由于只有一个正方形,所以除以4后结果仍然是1。
运行解析
  1. 输入解析

    • 第一个数字 5 表示点的数量。
    • 接下来的 10 个数字表示 5 个点的坐标,每两个数字表示一个点的 (x, y) 坐标。
    • 具体点的坐标为:(0, 0), (1, 1), (1, 0), (0, 1), (2, 2)
  2. 算法逻辑

    • 首先,将点集存储在一个 HashMap 中,以便快速查找。键是点的字符串表示(x,y),值是布尔值(这里使用 true,但实际上值不重要,只关心键是否存在)。
    • 然后,通过两层循环枚举所有可能的点对 (x1, y1)(x2, y2)
    • 对于每对点,计算两组可能的正方形顶点 (x3, y3)(x4, y4),以及 (x5, y5)(x6, y6)
    • 检查这两组顶点是否都在点集中。如果在,则意味着找到了一个正方形。
    • 由于每个正方形通过其四条边会被计算四次,所以最终的结果需要除以 4。
  3. 具体计算

    • 对于点 (0, 0)(1, 1)
      • 计算 (x3, y3) = (-1, 1)(x4, y4) = (0, 2),这两个点不在点集中。
      • 计算 (x5, y5) = (1, -1)(x6, y6) = (2, 0),这两个点也不在点集中。
    • 对于点 (0, 0)(1, 0)
      • 计算 (x3, y3) = (0, 0)(x4, y4) = (1, -1),点 (0, 0) 在点集中,但 (1, -1) 不在。
      • 计算 (x5, y5) = (0, 0)(重复,忽略)和 (x6, y6) = (1, 1),这两个点都在点集中,但 (0, 0) 是起始点,所以这里不形成新的正方形。
    • 对于点 (0, 0)(0, 1)
      • 计算 (x3, y3) = (1, 0)(x4, y4) = (0, -1),点 (1, 0) 在点集中,但 (0, -1) 不在。
      • 计算 (x5, y5) = (-1, 0)(x6, y6) = (0, 1)(重复,忽略),这里也不形成新的正方形。
    • 对于点 (0, 0)(2, 2)
      • 计算 (x3, y3) = (-2, 2)(x4, y4) = (0, 4),这两个点不在点集中。
      • 计算 (x5, y5) = (2, -2)(x6, y6) = (4, 0),这两个点也不在点集中。
    • 类似地,检查其他点对,但在这个特定的点集中,只有一对点 (1, 0)(0, 1) 会形成正方形 (1, 0), (0, 1), (0, 0), (1, 1)
  4. 结果

    • 在这个例子中,只有一个正方形,即 (0, 0), (1, 0), (1, 1), (0, 1)
    • 由于每个正方形被计算了 4 次,所以初始计数为 4,最终结果为 4 / 4 = 1

因此,对于输入 5 0 0 1 1 1 0 0 1 2 2,输出结果为 1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值