[leetcode] 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]]

 分析:题目意思理解起来并不是很难,二维数组的每一行代表平面上的一个点,任意一个点到其他两个点距离相同时,视为一个解。这里要注意的是其他两个点也是分先后顺序的,也就是可以看成是一个排列问题。有了这个作为基础,首先想到的就是计算所有点之间的距离,并且用一个二维矩阵保存下来。然后去遍历这个二维矩阵的每一行,假设一行有m个相同距离为1的点,那么就是A(m,2)。
        有了上面的分析,首先想到找排列公式,在网上找了一个递归版本的求排列和组合的代码,用java描述如下:
 1     /**
 2      * 计算阶乘数,即n! = n * (n-1) * ... * 2 * 1 
 3      * @param n
 4      * @return
 5      */
 6     private static long factorial(int n) {
 7         long sum = 1;
 8         while( n > 0 ) {
 9             sum = sum * n--;
10         }
11         return sum;
12     }
13     /**
14      * 排列计算公式A<sup>m</sup><sub>n</sub> = n!/(n - m)!
15      * @param m
16      * @param n
17      * @return
18      */
19     public static long arrangement(int m, int n) {
20         return m <= n ? factorial(n) / factorial(n - m) : 0;
21     }
22     /**
23      * 组合计算公式C<sup>m</sup><sub>n</sub> = n! / (m! * (n - m)!)
24      * @param m
25      * @param n
26      * @return
27      */
28     public static long combination(int m, int n) {
29         return m <= n ? factorial(n) / (factorial(m) * factorial((n - m))) : 0;
30     }

      那么本题的代码如下:

 1     int res = 0;
 2     public int numberOfBoomerangs(int[][] points) {
 3         int n = points.length;
 4         double[][] distance = new double[n][n];
 5         for ( int i = 0 ; i < n ; i ++ ){
 6             for ( int j = 0 ; j < n ; j ++ ){
 7                 distance[i][j] = Math.sqrt((points[j][0]-points[i][0])*(points[j][0]-points[i][0])+(points[j][1]-points[i][1])*(points[j][1]-points[i][1]));
 8             }
 9         }
10         Map<Double,Integer> map = new HashMap<>();
11         for ( int i = 0 ; i < n ; i ++ ){
12             map.clear();
13             for ( int j = 0 ; j < n ; j ++ ){
14                 map.put(distance[i][j],map.getOrDefault(distance[i][j],0)+1);
15             }
16             for ( int value : map.values() ){
17                 if ( value >= 2 ) calcnum(value);
18             }
19         }
20         return res;
21     }
22     private void calcnum(int value) {
23         res += factorial(value) / factorial(value-2);
24     }
25     private static long factorial(int n) {
26         long sum = 1;
27         while( n > 0 ) {
28             sum = sum * n--;
29         }
30         return sum;
31     }

      最后运行时间117ms,超过94.7%的人。


      但是,还是有很大的优化空间,首先在计算距离矩阵的时候,没必要先全部保存下来然后再遍历,可以一边计算,一边用Map记录;而且对于A(m,2),计算下来的结果就是m*(m-1),所以也没必要再用递归来做了;因为只要找距离相同的点的个数,也不需用求根号了;这样优化下来,第二版代码如下:

 1 class Solution {
 2     public int numberOfBoomerangs(int[][] points) {
 3         int res = 0;
 4         Map<Double,Integer> map = new HashMap<>();
 5         int n = points.length;
 6         for ( int i = 0 ; i < n ; i ++ ){
 7             for ( int j = 0 ; j < n ; j ++ ){
 8                 double d = (points[j][0]-points[i][0])*(points[j][0]-points[i][0])+(points[j][1]-points[i][1])*(points[j][1]-points[i][1]);
 9                 map.put(d,map.getOrDefault(d,0)+1);
10             }
11             for ( int value : map.values() ){
12                 if ( value >= 2 ) res += value*(value-1);
13             }
14             map.clear();
15         }
16         return res;
17     }
18 }

      运行时间97ms,超过99%的人。

原文地址:https://www.cnblogs.com/boris1221/p/9289642.html