1. 题目描述
https://leetcode.com/problems/number-of-boomerangs/#/description
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 i and 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:
2Explanation:
The two boomerangs are [[1,0],[0,0],[2,0]] and [[1,0],[2,0],[0,0]]Subscribe to see which companies asked this question.
2. 解题思路
我们的初始思路就是使用暴力求解,遍历所有可能的排列组合共计
A33
种,然后逐个判断他们是否满足我们的需求, 然而代码提交之后发现,超时了,因为这种实现算法的时间复杂度达到了
O(n)3
, 因而我们考虑是否可以降低这个算法复杂度。
我们可以以一个点为基准向外做圆, 如果有多个点在圆上,那么就可以直接利用排列组合求解得到对应这个距离的所有符合要求的解的个数
如图所示,图上有很多个点,我们现在以A点为圆心向外做圆,其中, 1,2,3,4在这个圆上,那么对应这个圆,我们一定可以找到
A24=12
种符合题目要求的boomerangs的数目
3. 实现代码
3.1 first-version
暴力求解
class Solution {
public:
int numberOfBoomerangs(vector<pair<int, int>>& points) {
int boomranges_num = 0;
for (size_t i = 0; i < points.size(); i++){
for (size_t j = 0; j < points.size(); j++){
if (j == i)
continue;
for (size_t k = 0; k < points.size(); k++){
if (k == i || k == j)
continue;
if (isBoomerangs(points[i], points[j], points[k]))
boomranges_num++;
}
}
}
return boomranges_num;
}
protected:
inline bool isBoomerangs(const pair<int, int> & first,
const pair<int, int> & second, const pair<int, int> & third){
return getDistance(first, second) == getDistance(first, third);
}
inline double getDistance(const pair<int, int> & first, const pair<int, int> & second){
return sqrt(pow(first.first - second.first, 2)
+ pow(first.second - second.second, 2));
}
};
显示效果:
3.2 second version
我们采用画圆的思路,算法复杂度 O(n2)
class Solution {
public:
int numberOfBoomerangs(vector<pair<int, int>>& points) {
int numbers = 0;
for (size_t i = 0; i < points.size(); i++){
map<double, int> DisOccurTimes;
for (size_t j = 0; j < points.size(); j++){
if (j == i)
continue;
DisOccurTimes[getDistance(points[i], points[j])]++;
}
for (auto item : DisOccurTimes){
numbers += item.second * (item.second - 1);
}
}
return numbers;
}
protected:
inline double getDistance(const pair<int, int> & first, const pair<int, int> & second){
return sqrt(pow(first.first - second.first, 2)
+ pow(first.second - second.second, 2));
}
};
显示效果:
3.3 third version
分析第二版的代码,我们发现其实我们这里使用的开方运算是没有多大用处的,完全可以省略这个步骤
class Solution {
public:
int numberOfBoomerangs(vector<pair<int, int>>& points) {
int numbers = 0;
for (size_t i = 0; i < points.size(); i++){
map<double, int> DisOccurTimes;
for (size_t j = 0; j < points.size(); j++){
if (j == i)
continue;
DisOccurTimes[getDistanceSquare(points[i], points[j])]++;
}
for (auto item : DisOccurTimes){
numbers += item.second * (item.second - 1);
}
}
return numbers;
}
protected:
inline double getDistanceSquare(const pair<int, int> & first, const pair<int, int> & second){
return pow(first.first - second.first, 2)
+ pow(first.second - second.second, 2);
}
};
运行效果:
3.4 forth version
我们突发奇想,这边运算的时候完全可以直接使用int类型嘛,为啥非得用double类型呢,我们是不是可以不要使用标准库的pow函数呢, 然而通过测试发现还是使用pow函数整体效率是最好的, 其他修改效果就不展示了,有兴趣的可以自行尝试。
3.5 fivth version
参考了牛人的代码之后,我们想到可以将之前版本中的代码种的for循环合并起来,由此得到如下代码:
class Solution {
public:
int numberOfBoomerangs(vector<pair<int, int>>& points) {
int numbers = 0;
for (size_t i = 0; i < points.size(); i++){
map<double, int> DisOccurTimes;
for (size_t j = 0; j < points.size(); j++){
if (j == i)
continue;
numbers += 2 * DisOccurTimes[getDistanceSquare(points[i], points[j])]++;
}
}
return numbers;
}
protected:
inline double getDistanceSquare(const pair<int, int> & first, const pair<int, int> & second){
return pow(first.first - second.first, 2)
+ pow(first.second - second.second, 2);
}
};
运行效果:
4. 参考代码
https://discuss.leetcode.com/topic/66574/7-lines-1050-ms-c
注意 hypot 指的是求对象的平方根(神奇啊) http://en.cppreference.com/w/cpp/numeric/math/hypot
下面的解法传说是150ms +- 10ms
int numberOfBoomerangs(const vector<pair<int, int>>& points) {
short len{points.size()};
unordered_map<int, int> mymap;
int total{};
const pair<int, int> *data{points.data()};
for (short ii = 0; ii < len; ++ii) {
for (short jj = 0; jj < len; ++jj) {
if (ii == jj)
continue;
total += mymap[((data + ii)->first - (data + jj)->first)*((data + ii)->first - (data + jj)->first) + \
((data + ii)->second - (data + jj)->second)*((data + ii)->second - (data + jj)->second)]++;
}
mymap.clear();
}
return 2*total;
}