【leetcode 447. 回旋镖的数量】审慎思考与推倒重来

447. 回旋镖的数量

题目描述

给定平面上 **n **对 互不相同 的点 points ,其中 points[i] = [xi, yi]回旋镖 是由点 (i, j, k) 表示的元组 ,其中 ij 之间的距离和 ik 之间的欧式距离相等(需要考虑元组的顺序)。

返回平面上所有回旋镖的数量。

原始思路

根据题目描述,所谓回旋镖就是对于一个点i,存在另外两个点到该点的距离相等

以下图为例,点(0,0)(0,2)(2,0)的距离是相通的,这就是一个回旋镖。同样的,点(2,2)(0,2)(2,0)也构成一个回旋镖。

请添加图片描述

大概理解题目的含义后,最直接的想法就是遍历,通过三重遍历分辨判断是否为回旋镖,最后的统计数目就是需要的结果。代码实现如下:

class Solution {
private:
    // 判断点i与点j、点k是否构成回旋镖
    // ps:这里省略了开方运算
    bool isBoomeranges(vector<int>& i, vector<int>& j, vector<int>& k) {
        return ((j[1] - i[1]) * (j[1] - i[1])) + ((j[0] - i[0]) * (j[0] - i[0])) == ((k[1] - i[1]) * (k[1] - i[1])) + ((k[0] - i[0]) * (k[0] - i[0]));
    }
public:
    int numberOfBoomerangs(vector<vector<int>>& points) {
        int res = 0;
        int pointNum = points.size();
        for(int i = 0;i < pointNum;++i) {
            for(int j = 0;j < pointNum;++j) {
                for(int k = 0;k < pointNum;++k) {
                    if(i == j || i == k || j == k) {
                        // 同一个点不算
                        continue;
                    }
                    if(isBoomeranges(points[i], points[j], points[k])) {
                        ++res;
                    }
                }
            }
        }
        return res;
    }
};

三重循环,不出意外地超时了……

image.png

试图挽回,空间换时间

三重循环每次都要计算距离,肯定是做了很多重复运算的,或许可以用空间换时间,

尝试代码如下:

class Solution {
public:
    int numberOfBoomerangs(vector<vector<int>>& points) {
        int res = 0;
        int pointNum = points.size();
        vector<vector<long>> dis(pointNum, vector<long>(pointNum, 0)); // 记录点与点之间的“距离”
        for(int i = 0;i < pointNum;++i) {
            for(int j = i + 1;j < pointNum;++j) {
                dis[j][i] = dis[i][j] = ((points[j][1] - points[i][1]) * (points[j][1] - points[i][1])) + ((points[j][0] - points[i][0]) * (points[j][0] - points[i][0]));
            }
        }
        for(int i = 0;i < pointNum;++i) {
            for(int j = 0;j < pointNum;++j) {
                for(int k = 0;k < pointNum;++k) {
                    if(i == j || i == k || j == k) {
                        continue;
                    }
                    if(dis[i][j] == dis[i][k]) {
                        ++res;
                    }
                }
            }
        }
        return res;
    }
};

结果从通过25个测试用例提升到通过28个。改善了,但又没完全改善。

image.png

到这里,意识到应该是解决方案本身的时间复杂度 O ( n 3 ) O(n^3) O(n3)就太高了。

回归本源,方法为王

虽然上面的思路简单易懂,但也把我带入“歧途”,没有深入审视题目中的含义。

所以遍历思路走到尽头后,不得不重新审视题目。

三重循环中有很多计算是重复的,还是以开头的例子做讲解,对于点(1,1),它需要分别判断:

  1. (0,0)(0,2)是否构成回旋镖
  2. (0,0)(2,2)是否构成回旋镖
  3. (0,0)(2,0)是否构成回旋镖
  4. (0,2)(0,0)是否构成回旋镖
  5. (0,2)(2,2)是否构成回旋镖
  6. (0,2)(2,0)是否构成回旋镖
  7. (2,2)(0,0)是否构成回旋镖
  8. (2,2)(0,2)是否构成回旋镖
  9. (2,2)(2,0)是否构成回旋镖
  10. (2,0)(0,0)是否构成回旋镖
  11. (2,0)(0,2)是否构成回旋镖
  12. (2,0)(2,2)是否构成回旋镖

在这个过程中,(1,1)(0,0)(0,2)(2,2)(2,0)的距离,分别被算了6遍。

但实际上,(1,1)到这四个点的距离都是相同的,任取两个点都能和(1,1)构成回旋镖,再加上顺序敏感的题目要求(既 [ ( 1 , 1 ) , ( 0 , 0 ) , ( 0 , 2 ) ] [(1,1),(0,0),(0,2)] [(1,1),(0,0),(0,2)] [ ( 1 , 1 ) , ( 0 , 2 ) , ( 0 , 0 ) ] [(1,1),(0,2),(0,0)] [(1,1),(0,2),(0,0)]是两个回旋镖),利用排列数计算就能替代多余计算。

whiteboard_exported_image-7.png

所以,对于某个点i,只需统计其他点与i之间的距离,然后利用排列数就可以计算出回旋镖的数目。
比如上面的例子中,距离为 2 \sqrt{2} 2 的点对有4个,那么 A 4 2 = 4 × 3 = 12 A^2_4 = 4 \times 3 = 12 A42=4×3=12

算法步骤:

  1. 遍历所有点
  2. 对于某个点i,统计与其他点的距离长度
  3. 对每个距离长度的数目,计算排列数
  4. 所有排列数之和即为答案
class Solution {
private:
    int distance(const vector<int>& p1, const vector<int>& p2) {
        // 计算两点之间的“距离”
        return (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]);
    }
public:
    int numberOfBoomerangs(vector<vector<int>>& points) {
        int res = 0;
        int pointNum = points.size();
        for(int i = 0;i < pointNum;++i) {
            // 遍历所有点
            unordered_map<int, int> disNumMp;
            for(int j = 0;j < pointNum;++j) {
                // 统计该点与其他之间距离长度的数目
                // 只有该点自己到自己的长度为0,所以0对应的数目一定为0,不影响最终结果计算,无需剔除
                ++disNumMp[distance(points[i], points[j])];
            }
            for(auto it = disNumMp.begin();it != disNumMp.end();++it) {
                // 计算排列数
                res += (it->second * (it->second - 1));
            }
        }
        return res;
    }
};

小感悟

有些时候,人容易对一开始选择的路径产生依赖,不推倒重来就难以跳脱。

审慎的思考和选择或许可以避免弯路,但更多时候还是要走到南墙才能意识到选择的对错。

所以,要有审慎选择的过程,也要有推倒重来的勇气!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/305381.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

加速科技ST2500 数模混合信号测试设备累计装机量突破500台!

国产数字机&#xff0c;测试中国芯&#xff01;新年伊始&#xff0c;国产半导体测试设备领军企业加速科技迎来了振奋人心的一刻&#xff0c;ST2500 数模混合信号测试设备累计装机量突破500台&#xff01;加速科技凭借其持续的创新能力、完善的解决方案能力、专业热忱的本地化服…

企业级快速开发平台可以用在什么行业?优点多吗?

应用专业的企业级快速开发平台可以带来什么效果&#xff1f;目前&#xff0c;低代码技术平台在很多领域都获得了广泛应用和推广&#xff0c;在实现高效率办公、流程化办公和数字化发展中扮演了非常重要的角色&#xff0c;具有举足轻重的作用。针对这个话题&#xff0c;现在将给…

外汇天眼:台北妇女轻信假投资诈骗话术,小赚1万却惨赔1500万

当今社会物价急速上涨&#xff0c;许多民众为了避免资产因通膨缩水&#xff0c;纷纷开始寻找各种能增加收入的渠道&#xff0c;因此投资理财日渐受到重视。 然而&#xff0c;诈骗集团也注意到这趋势&#xff0c;并且推出虚假的投资平台或方案&#xff0c;以各种话术行骗。 不久…

【css】快速实现鼠标悬浮变色效果

<div class"nav-item"><div class"ic-img"></div><div>切换</div> </div>.nav-item {width: 100rem;height: 45rem;line-height: 45rem;display: flex;text-align: center;justify-content: center;align-items: cent…

用python提取word中的所有图片

使用word中提取的方式图片会丢失清晰度&#xff0c;使用python写一个脚本&#xff0c;程序运行将弹出对话框选择一个word文件&#xff0c;然后在弹出一个对话框选择一个文件夹保存word中的文件。将该word中的所有图片都保存成png格式&#xff0c;并命名成image_i的样式。 程序…

go image.DecodeConfig 和image.Decode 不能同时使用吗

问题场景&#xff1a;在同时使用go image.DecodeConfig 和image.Decode获取图片信息时&#xff0c;报错提示&#xff1a; 无法读取图像配置 image: unknown format package mainimport ("fmt""github.com/golang/freetype""image""image/d…

软件压测工具有哪些功能和特点

目前市场上有许多成熟的压测工具&#xff0c;开发人员可以根据自己的项目特点和需求选择合适的工具进行压力测试。本文将介绍软件压测工具的功能和特点&#xff1a; 一、软件压测工具定义 软件压测工具是一种专门设计用于模拟大量用户并发访问系统的工具。通过模拟真实场景中的…

1876_电感的特性小结

Grey 全部学习内容汇总&#xff1a; GitHub - GreyZhang/g_hardware_basic: You should learn some hardware design knowledge in case hardware engineer would ask you to prove your software is right when their hardware design is wrong! 1876_电感的特性小结 主要是…

服务器运维工具推荐——站长、运维必看!

服务器运维是确保服务器系统稳定运行并保持高效性的重要工作。为了提高运维工作的效率&#xff0c;使用一些优秀的服务器运维工具是非常必要的。使用了解多款运维工具后&#xff0c;总结了几款还不错的工具&#xff1a; 1、Zabbix &#x1f4d2;简介&#xff1a;Zabbix是一款开…

分析一个项目(微信小程序篇)二

目录 首页&#xff1a; 发现&#xff1a; 购物车&#xff1a; 我的&#xff1a; 分析一个项目讲究的是如何进行对项目的解析分解&#xff0c;进一步了解项目的整体结构&#xff0c;熟悉项目的结构&#xff0c;能够知道每个组件所处在哪个位置&#xff0c;发挥什么作用。 接…

U盘、硬盘无法打开,修复RAW磁盘或分区,硬盘变成raw格式如何恢复,数据恢复

本文持续更新&#xff0c;针对遇到的数据丢失问题进行详细记录 磁盘变成RAW的可能原因 突然断电或关机文件系统丢失或损坏病毒或恶意软件感染坏扇区磁盘损坏 以下解决方案针对非病毒损坏 通过Windows自带的工具进行恢复&#xff08;CHKDSK命令&#xff09; 1.连接硬盘 2.…

自动化测试框架搭建(流程详解)

说起自动化测试&#xff0c;我想大家都会有个疑问&#xff0c;要不要做自动化测试&#xff1f; 自动化测试给我们带来的收益是否会超出在建设时所投入的成本&#xff0c;这个嘛别说是我&#xff0c;即便是高手也很难回答&#xff0c;自动化测试的初衷是美好的&#xff0c;而测试…

用PreMaint引领先进的预测性维护

在设备维护领域&#xff0c;预测性维护成为一项利用先进技术和巧妙工具的数据驱动战略。这一战略通过条件监控和数据分析&#xff0c;以主动维护的方式识别潜在的设备缺陷&#xff0c;避免问题升级。高效使用PreMaint预测性维护工具可不仅节省时间和成本&#xff0c;更显著提升…

信息时代的品牌危机与应对之道:迅腾文化的价值“从心所欲不逾矩”

在瞬息万变的信息时代&#xff0c;企业品牌面临着时代的危机与挑战。在这个时代&#xff0c;自诩能穿透未来迷雾的先知已然无法满足企业的需求&#xff0c;而居安思危、行死而生的“惶者”才是企业所需要的。迅腾文化正是这样的存在&#xff0c;积极倾听企业&#xff0c;融汇未…

Linux第22步_安装CH340驱动和串口终端软件MobaXterm

开发板输出信息通常是采用串口&#xff0c;而计算机通常是USB接口&#xff0c;为了让他们之间能够交换数据&#xff0c;我们通常采用USB转串口的转换器来实现。目前市场上的串口转换器大多是采用CH340芯片来实现的&#xff0c;因此我们需要在计算中安装一个CH340驱动程序&#…

LabVIEW在设备状态监测与故障诊断中的应用

在现代工业自动化领域&#xff0c;LabVIEW的系统设计平台在设备状态监测与故障诊断中扮演着举足轻重的角色。通过提供一个可视化和数据流编程语言&#xff0c;LabVIEW大大提升了设备安全监测的效率&#xff0c;减少了系统维护成本&#xff0c;同时增强了设备的可靠性和可维护性…

时序预测 | Matlab基于灰色隐马尔可夫模型(HMMP-GM11)的时间序列预测

时序预测 | Matlab基于灰色隐马尔可夫模型(HMMP-GM11)的时间序列预测 目录 时序预测 | Matlab基于灰色隐马尔可夫模型(HMMP-GM11)的时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 灰色HMMP-GM11改进模型,通过引入隐马尔可夫模型(HMM)来对原始数据进行状态分…

QT第二天

使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#xff0c;密码是否为&…

STM32---WWDG(窗口看门狗)超详细

写在前面&#xff1a;上节我们学习了独立看门狗&#xff08;IWDG&#xff09;相关知识&#xff0c;本节我们来学习另外一个看门狗——WWDG窗口看门狗&#xff0c;内容并不难&#xff0c;但是目前这些看门狗的具体内容&#xff0c;还没有得到一个很好的应用&#xff0c;还是先学…

基于apache的http文件服务配置

背景&#xff1a; 公司的产品使用的第三方模组可以OTA&#xff0c;厂家提供的是window开启软件&#xff0c;这样就可以在本机做http下载服务器&#xff0c;然后使用端口映射的方式&#xff0c;公开到外网&#xff0c;这样就可以进行4G网络访问内网服务器了。但这个有个弊端&am…