# 【Day 20】回旋镖的数量
# 题目描述
给定平面上 n 对不同的点,“回旋镖” 是由点表示的元组 (i, j, k) ,其中 i 和 j 之间的距离和 i 和 k 之间的距离相等(需要考虑元组的顺序)。
找到所有回旋镖的数量。你可以假设 n 最大为 500,所有点的坐标在闭区间 [-10000, 10000] 中。
示例:
输入:
[[0,0],[1,0],[2,0]]
输出:
2
解释:
两个回旋镖为 [[1,0],[0,0],[2,0]] 和 [[1,0],[2,0],[0,0]]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-boomerangs
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
# 我的回答
# 解法一
# 时间复杂度 O(n*n)
# 空间复杂度 O(n)
var numberOfBoomerangs = function (points) {
let res = 0
for (let i = 0; i < points.length; i++) {
let map = {}
for (let j = 0; j < points.length; j++) {
let x = points[j][0] - points[i][0]
let y = points[j][1] - points[i][1]
let dist = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
map[dist] = map[dist] ? map[dist] + 1 : 1
}
for (let i in map) {
res += map[i] * (map[i] - 1)
}
}
return res
};
# 参考回答
# #447 回旋镖的数量
多读两遍题,大概就明白了题意:就是找出所有符合三个点 x,y,z,并且 dis(x,y)=dis(x,z)这种点的个数。首先要明确两点间距离怎么计算,忘了是小学还是初中的知识了:
$$x=(x1,x2)$$
$$y=(y1,y2)$$
$$dis(x,y) = \sqrt{(x1 - y1)^{2} + (x2 - y2) ^{2}}$$
由于求的是算数平方根,所以我们算距离的时候也没必要开根号了
我们可以很容易地想到暴力解法,也就是来个三重循环
public int numberOfBoomerangs(int[][] points) { if (points == null || points.length <= 2) return 0; int res = 0; for (int i = 0; i < points.length; i++) { for (int j = 0; j < points.length; j++) { if (i == j) continue; for (int k = 0; k < points.length; k++) { if (k == i || k == j) continue; if (getDistance(points[i], points[j]) == getDistance(points[i], points[k])) res++; } } } return res; } private int getDistance(int[] x, int[] y) { int x1 = y[0] - x[0]; int y1 = y[1] - x[1]; return x1 * x1 + y1 * y1; }
这就相当于把题目翻译了一遍,但是提交就会发现 TLE 了,也不难发现时间复杂度是$O(N^{3})$,
也就是我们需要优化代码了。。。首先题目说 n 个点不同且答案考虑元组顺序,那么我们最外层循环是跑不掉了,因为需要固定每一个点。
里面两层循环可不可以优化一下呢,其实不难想,当我们固定其中一个点 A 的时候,并且想算距离为 3 的点的个数,那么我们就找出所有和点 A 距离为 3 的点,然后来一个简单的排列组合嘛!比如找到了 n 个距离为 3 的点,那么我们选择第二个点有 n 种方案,选择第三个点有(n - 1)个方案,那么固定点 A 且距离为 3 的所有可能就是 n*(n-1),这是说距离为 3,还有许多其他距离呢,这不就又回到了我们统计元素频率的问题上了嘛,当然哈希表用起来!上代码:
public int numberOfBoomerangs(int[][] points) { if (points == null || points.length <= 2) return 0; int res = 0; Map<Integer, Integer> equalCount = new HashMap<>(); for (int i = 0; i < points.length; ++i) { for (int j = 0; j < points.length; ++j) { int dinstance = getDistance(points[i], points[j]); equalCount.put(dinstance, equalCount.getOrDefault(dinstance, 0) + 1); } for (int count : equalCount.values()) res += count * (count - 1); equalCount.clear(); } return res; } private int getDistance(int[] x, int[] y) { int x1 = y[0] - x[0]; int y1 = y[1] - x[1]; return x1 * x1 + y1 * y1; }
这样时间复杂度就被优化为$O(N^{2} * max(different_distance_count))$
ps: 希望大家自己动手实现输入输出格式,输入格式可以如下:
第一行代表n个点,后面有n行数据 用空格分割元素 5 1 2 0 1 0 2 3 2 2 3