leetcode 447. Number of Boomerangs解题笔记

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:
2

Explanation:
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;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值