LeetCode之路:447. Number of Boomerangs
来源:互联网 发布:娃娃编程scratchjr安卓 编辑:程序博客网 时间:2024/05/21 22:29
一、引言
这道题还算比较有意思。
先看看题目吧:
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]]
照惯例简单翻译下:
给定 n 个成对的平面上的点,一个 “boomerang” 就是一组元组 (i, j, k),其中 i 到 j 的距离等于 i 到 k 的距离(这组点的顺序决定了元组是否相同)
请找到 “boomerang” 的个数。你可以假定 n 不会超过 500,并且坐标系不会超过 [-10000, 10000] 的范围。
根据题意,我们了解到了我们要在 n 个平面上的点中寻找这么一个元组:
(i, j, k) ,其中 i 到 j 的距离等于 i 到 k 的距离
我们只需要在 n 个点中寻找这个元组能够拼凑出来的个数即可。
其实这道题思路还是比较简单的:
首先,遍历所有的点
然后,以一个点为基准点计算与其他所有点的距离,将距离记录在一个缓存映射中
最后,将每个点中的距离缓存映射中的出现次数大于 2 的记录进行排列计算(出现次数中取 2 的排列),最后叠加起来即可
思考到这一步,剩下的就是如何编写代码了。
二、核心:出现次数中取 2 的排列
根据引言中的思路,编写代码如下:
// my solution 1 , runtime = 329 msclass Solution1 {public: int numberOfBoomerangs(vector<pair<int, int>>& points) { int count = 0; for (auto cur_pt : points) { map<double, int> distance; for (auto otr_pt : points) if (cur_pt != otr_pt) distance[pow(otr_pt.first - cur_pt.first, 2) + pow(otr_pt.second - cur_pt.second, 2)]++; for (auto dis : distance) if (dis.second > 1) count += dis.second * (dis.second - 1); } return count; }};
可以看到这段代码中:
对所有点进行了遍历,以达到取到每个点的功能
std::map 实现了计算的举例结果的出现次数的记录。计算两点间的距离使用了 std::pow 函数
最后的一个 for 循环,将每一个点的距离缓存进行遍历,将其中出现次数大于了 2 次的进行组合计算,比如距离计算为 1 的点出现了 3 次,那么 3 中取 2 的排列(之所以是排列,因为顺序影响元组),也就是 3 * 2 = 6 次
这个方法比较简单,其实还是有优化空间的。
比如,我们没必要除去本身的点的计算(因为始终为 0 ),此处可以简化代码行数。
再比如这里的计算距离的公式,可以使用 std:hypot:
distance[hypot(otr_pt.first - cur_pt.first, otr_pt.second - cur_pt.second)]++;
计算两个点之间的距离,使用 std::hypot 函数最合适不过了。
想要详细了解这个函数的同学可以点击这里:
C++在线参考手册之std::hypot。
三、殊途同归:最高票答案难以理解的算法
做到了这里,尽管已经 AC 了,但是还是要看看最高票答案的玄妙:
// perfect solution class Solution2 {public: int numberOfBoomerangs(vector<pair<int, int>>& points) { int booms = 0; for (auto &p : points) { unordered_map<double, int> ctr(points.size()); for (auto &q : points) booms += 2 * ctr[hypot(p.first - q.first, p.second - q.second)]++; } return booms; }};
这个方法比我的方法少了一次遍历,也就是少了那一次对于映射的遍历,也就是说最高票答案将缓存 map 的计算移到了第二次循环中去了。
让我们仔细看看,他是怎么计算的:
当获取到了基准点到每个点的距离的时候,我的方法是计算排列(出现次数中取 2 的排列),而他则是 2 * 上一次的出现值
让我们想想,这样可以计算结果吗?答案当然是可以的。让我们想想啊:
距离为 1 的点第 1 次出现:
booms += 2 * 0; // 只加了 0 次
距离为 1 的点第 2 次出现:
booms += 2 * 1; // 加了 2 次
距离为 1 的点第 3 次出现:
booms += 2 * 2; // 加了 4 次也就是说,我们可以这么想,当前的基准点到两个点的排列即为我们的 “boomerang” 点,那么每增加一个可以凑成同样距离的 “boomerang” 点之后,我们其实就要增加
2 * 当前同距离点的个数
个 “boomerang” 元组可能(也就是该点到同距离的各个点之后,再换个位置,所以 * 2)
经过了我的分析,相信你也理解了最高票答案的算法。
这里最高票答案除了使用了特别的算法之外,还使用了 unordered_map 来提高运行效率,非常可取。
四、总结
这道题还是比较有趣的,做出来也没花多少时间。
利用公司中午的午休时间写的博客,依然喜爱着 LeetCode :)
To be Stronger!
- LeetCode之路:447. Number of Boomerangs
- LeetCode 447. Number of Boomerangs
- leetcode:447. Number of Boomerangs
- leetcode 447. Number of Boomerangs
- LeetCode 447. Number of Boomerangs
- 【LeetCode】 447. Number of Boomerangs
- [LeetCode]447. Number of Boomerangs
- [leetcode] 447. Number of Boomerangs
- Leetcode 447. Number of Boomerangs
- LeetCode 447. Number of Boomerangs
- Leetcode-447. Number of Boomerangs
- [LeetCode]447. Number of Boomerangs
- 【Leetcode】447. Number of Boomerangs
- leetcode 447. Number of Boomerangs
- [leetcode]: 447. Number of Boomerangs
- [LeetCode] 447. Number of Boomerangs
- [LeetCode]447.Number of Boomerangs
- leetcode 447. Number of Boomerangs
- 批处理定时自动更新SVN
- json使用
- 从任务到可视化,如何理解LSTM网络中的神经元 By 机器之心2017年7月03日 14:29 对人类而言,转写是一件相对容易并且可解释的任务,所以它比较适合用来解释神经网络做了哪些事情,以及神经网
- mysql升级
- SQLite基本用法
- LeetCode之路:447. Number of Boomerangs
- 安卓刷量技术揭秘(二) 高级攻防技巧
- 知人知面需知心——论人工智能技术在推荐系统中的应用
- JAVA实现单点登录
- netbeans xdebug 调试PHP discuz详解
- 小M开发_jsp_Servlet_day170704
- vue如何处理返回数据,再进行分类展示
- 如何用 Python 和机器学习帮你决策?
- 糊糊的前端学习笔记——如何将文本行数确定为固定行,并将多余部分用省略号表示【Day04】