Leetcode 447:Number of Boomerangs

Leetcode 447:Number of Boomerangs

You are given n points in the plane that are all distinct, where points[i] = [xi, yi]. A boomerang is a tuple of points (i, j, k) such that the distance between i and j equals the distance between i and k (the order of the tuple matters).

Return the number of boomerangs.

说人话:

给定平面上 n 对互不相同的点 points ,其中 points[i] = [xi, yi] 。回旋镖是由点 (i, j, k) 表示的元组 ,其中 i 和 j 之间的距离和 i 和 k 之间的距离相等(需要考虑元组的顺序)。

返回平面上所有回旋镖的数量。

几个要点:

  • 点是不同的点
  • 点 i 是枢纽
  • 返回的是回旋镖的数量,不是具体的回旋镖
  • n == points.length
  • 1 <= n <= 500:说明我们可以接受 O(n2) 级别的算法
  • points[i].length == 2
  • -104 <= xi, yi <= 104,所以算距离的时候不会出现溢出

示例:

Leetcode 447:Number of Boomerangs

[法1] 暴力法

思路
  • 遍历所有点的情况
  • 三层循环,找到符合条件的元组
  • 记录元组个数
代码
class Solution {
    public int numberOfBoomerangs(int[][] points) {

        int result = 0;

        //三层遍历
        for(int a=0;a<points.length;a++){
            for(int b=0;b<points.length;b++){
                for(int c=0;c<points.length;c++){
                    //A.B.C为三个不同的点
                    if( a!=b && a!=c && b!=c){
                        //A.B的距离
                        int distanceAB = 
                          (points[a][0]-points[b][0])*(points[a][0]-points[b][0])+ 
                          (points[a][1]-points[b][1])*(points[a][1]-points[b][1]);
                        //A.C的距离
                        int distanceAC = 
                          (points[a][0]-points[c][0])*(points[a][0]-points[c][0])+ 
                          (points[a][1]-points[c][1])*(points[a][1]-points[c][1]);
                        //距离相等则累加
                        if( distanceAB == distanceAC){
                            result++;
                        }
                    }

                }
            }
        }
        return result;
    }
}
提交结果
Leetcode 447:Number of Boomerangs
代码分析
  • 时间复杂度:O(n3)
  • 空间复杂度:O(1)
改进思路

因为 N 的级别为 500,所以我们可以接受 n2 的复杂度, n3 就太大了。我们需要想办法将时间复杂度降为 O(n2) 甚至更低。

[法2] 查找表灵活选择键值

思路

我们可以发现题目中 点 i 其实是一个枢纽,那么我们就可以对于每个 点 i,遍历其他剩余点到 点 i 的距离,然后看看相同距离的点有多少个,对这些相同距离的点进行排列组合 An2,就可以了。

整体思路如下:

  • 遍历所有点 i
  • 对每一个点 i 记录其他所有点与点 i 的距离,并记录相同距离的点的个数
  • 对这些相同距离的点进行排列组合 An2
  • 累计所有的点 i 得到回旋镖的个数
代码
class Solution {
    public int numberOfBoomerangs(int[][] points) {

        int result = 0;

        //遍历每一个点 i
        for(int i=0;i<points.length;i++){

            Map<Integer,Integer> map = new HashMap<>();

            //以 i 作为枢纽
            for(int j=0;j<points.length;j++){
                //记录其他点到点 i 的距离
                if( i!=j ){
                    //距离的平方
                    int distance = 
                    (points[i][0]-points[j][0])*(points[i][0]-points[j][0]) + 
                    (points[i][1]-points[j][1])*(points[i][1]-points[j][1]);

                    //统计相同记录的点的个数
                    Integer count = map.get(distance);
                    if(count !=null && count>0){
                        count++;
                        map.put(distance,count);
                    }else{
                        map.put(distance,1);
                    }
                }
            }

            //对这些相同距离的点进行排列组合
            Set<Integer> keys = map.keySet();
            for(Integer key: keys){
                Integer count = map.get(key);
                if(count != null && count >= 2){
                    result += (count)*(count-1);
                }
            }
        }
        return result;
    }
}
提交结果
Leetcode 447:Number of Boomerangs
代码分析
  • 时间复杂度:O(n2)。
  • 空间复杂度:因为对于每一个点 i 操作完成后都会释放 map,然后再申请,所以自始至终都只需要 O(n) 的辅助空间。
陷阱

本题中保证点的坐标在 [-10000,10000] 的范围内,所以算距离的时候不会发生整数溢出。如果没有这个条件的话,最好算距离的时候转为 long 或者 decimal 来进行计算,避免整数溢出。

上一篇:【uni-app】使用写字板,实现手写签名----直接使用版


下一篇:回旋镖的数量