[LeetCode] 447. Number of Boomerangs 解题报告

Given n points in the plane that are all pairwise distinct, a "boomerang" is a tuple of points (i, j, k) such that the distance between iand j equals the distance between i and k (the order of the tuple matters).

Find the number of boomerangs. You may assume that n will be at most 500 and coordinates of points are all in the range [-10000, 10000](inclusive).

Example:

Input:
[[0,0],[1,0],[2,0]]

Output:
2

Explanation:
The two boomerangs are [[1,0],[0,0],[2,0]] and [[1,0],[2,0],[0,0]]

这一题属于easy难度,不太困难。

首选的想法可能是3层循环暴力解法,这样会到O(n^3),显然是不可取的。

考虑到它只关心有多少组这样的数,而不关心有到底是哪几个数,所以有个O(n^2)解法。

思路:

针对一个点,我们算出来它到所有其他的距离。也就是说,只要我们找到某两个点到该点的距离相等,那么就可以找到一个三元组,由于题目里面说交换这两个点的位置算两组,这样算两个“boomerang”。如果找到了三个点到该点的距离相当,就可以形成6个boomerang。以此类推。

于是,我们想如何找这些距离相等的点的数量呢,很简单,用一个map存储,key=距离,value=数量。遍历这个map的values,计算所有的values就可以了。

该方法时间复杂度O(n^2),空间复杂度O(n):

public class Solution {
    public int numberOfBoomerangs(int[][] points) {
        int nResult = 0;
        for (int i = 0; i < points.length; i++) {
            Map<Integer, Integer> map = new HashMap<>();
            for (int j = 0; j < points.length; j++) {
                if (i == j) {
                    continue;
                }
                int nDis = getInstance(points[i], points[j]);
                map.put(nDis, map.getOrDefault(nDis, 0) + 1);
            }
            for (int ii : map.values()) {
                nResult += ii * (ii - 1);
            }
        }
        return nResult;
    }

    private int getInstance(int[] p1, int[] p2) {
        return (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]);
    }
}

上面代码用时271ms,注意一个细节,在内存循环开始之前,每次我都是new了一个map,我修改一下,成为如下代码,用时163ms:

public class Solution {
    public int numberOfBoomerangs(int[][] points) {
        int nResult = 0;
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < points.length; i++) {
            for (int j = 0; j < points.length; j++) {
                if (i == j) {
                    continue;
                }
                int nDis = getInstance(points[i], points[j]);
                map.put(nDis, map.getOrDefault(nDis, 0) + 1);
            }
            for (int ii : map.values()) {
                nResult += ii * (ii - 1);
            }
            map.clear();
        }
        return nResult;
    }

    private int getInstance(int[] p1, int[] p2) {
        return (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]);
    }
}
注意到map的位置,放到了循环外,并且在使用完以后,用了map.clear(),来清空这个map中的数据。map得到了重用,而不是每次重新new一个map,效率得到了巨大提升。也就是说,new一个map消耗的资源是非常高的。从源码中我们可以看到,hashmap.clear(),实际就是将table中所有的内容置为null。另外,很重要的是当再次put数据的时候,也起到了重用的效果。

    /**
     * Removes all of the mappings from this map.
     * The map will be empty after this call returns.
     */
    public void clear() {
        Node<K,V>[] tab;
        modCount++;
        if ((tab = table) != null && size > 0) {
            size = 0;
            for (int i = 0; i < tab.length; ++i)
                tab[i] = null;
        }
    }

而table,就是node的集合,node就是keyValue对。
    /**
     * The table, initialized on first use, and resized as
     * necessary. When allocated, length is always a power of two.
     * (We also tolerate length zero in some operations to allow
     * bootstrapping mechanics that are currently not needed.)
     */
    transient Node<K,V>[] table;

我们还可以进一步进行改进,用一个辅助数组来存储距离,也就是说算过一次的距离,不需要再算一次了,用时183ms。事实上这种改进对性能的提升非常小,这是因为一个距离只需要算两次,也就是说算一次再存起来的消耗,还不如算两次的。不像dp里面,算的距离需要用很多次。


public class Solution {
    public int numberOfBoomerangs(int[][] points) {
        int nResult = 0;
        int[][] nDisMatrix = new int[points.length][points.length];
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < points.length; i++) {
            for (int j = 0; j < points.length; j++) {
                if (i == j) {
                    continue;
                }
                int nDis = 0;
                if (nDisMatrix[i][j] > 0) {
                    nDis = nDisMatrix[i][j];
                } else {
                    nDis = getInstance(points[i], points[j]);
                    nDisMatrix[i][j] = nDis;
                    nDisMatrix[j][i] = nDis;
                }
                map.put(nDis, map.getOrDefault(nDis, 0) + 1);
            }
            for (int ii : map.values()) {
                nResult += ii * (ii - 1);
            }
            map.clear();
        }
        return nResult;
    }
        private int getInstance(int[] p1, int[] p2) {
        return (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]);
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值