【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;}
};

小感悟

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【算法设计与分析】网络流

目录 max-flow 和 min-cut流网络 Flow network最小割 Min-cut最大流 Max-flow Greedy algorithmFord–Fulkerson algorithm剩余网络 Residual networkFord–Fulkerson algorithm算法流程 最大流最小割理论 max-flow min-cut theorem容量扩展算法 capacity-scaling algorithm时间…

Golang : Bson\Json互转

代码 package bson_jsonimport ("encoding/json""errors""fmt""gopkg.in/mgo.v2/bson""os""testing" )type User struct {Name string json:"name,omitempty" bson:"name,omitempty"CSD…

大创项目推荐 深度学习实现语义分割算法系统 - 机器视觉

文章目录 1 前言2 概念介绍2.1 什么是图像语义分割 3 条件随机场的深度学习模型3\. 1 多尺度特征融合 4 语义分割开发过程4.1 建立4.2 下载CamVid数据集4.3 加载CamVid图像4.4 加载CamVid像素标签图像 5 PyTorch 实现语义分割5.1 数据集准备5.2 训练基准模型5.3 损失函数5.4 归…

三甲医院ADR智能监测系统源码,药品不良反应智能监测系统全套源码,java语言,自主研发

ADR智能监测系统源码&#xff0c;药品不良反应智能监测系统全套商业项目源码&#xff0c;自主版权 ADR监测上报系统是基于医院临床数据中心而建立&#xff0c;运用信息技术实现药品不良反应的智能监测、报告管理、知识库查询、统计分析等功能。 系统自动提取不良反应报告数据&…

(二)Explain使用与详解

explain中的列 sql语句: EXPLAIN SELECT * from user WHERE userId=1340; 执行结果: 1. id列 id列的编号是 select 的序列号,有几个 select 就有几个id,并且id的顺序是按 select 出现的顺序增长的。 id列越大执行优先级越高,id相同则从上往下执行,id为NULL最后执行…

如何在 Ubuntu 20.04 上安装和使用 Docker

前些天发现了一个人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;最重要的屌图甚多&#xff0c;忍不住分享一下给大家。点击跳转到网站。 如何在 Ubuntu 20.04 上安装和使用 Docker 介绍 Docker是一个可以简化容器中应用程序进程管理过程的应用程序。…

数据湖存储解决方案之Iceberg

1.Iceberg是什么&#xff1f; Apache Iceberg 是由 Netflix 开发开源的&#xff0c;其于2018年11月16日进入 Apache 孵化器&#xff0c;是 Netflix 公司数据仓库基础。Apache Iceberg设计初衷是为了解决Hive离线数仓计算慢的问题&#xff0c;经过多年迭代已经发展成为构建数据…

Qt实现简单的分割窗口

最近在学习一些关于Qt的新知识&#xff0c;今天来讲述下我学习到的窗口分割&#xff0c;如果有不正确的&#xff0c;大家可以指正哦~ 首先&#xff0c;先看一下实现之后的简单效果吧&#xff01;省的说的天花乱坠&#xff0c;大家却不知道说的是哪个部分。 功能实现 整体demo…

Spring事务控制

1.事务介绍 1.1什么是事务&#xff1f; 当你需要一次执行多条SQL语句时&#xff0c;可以使用事务。通俗一点说&#xff0c;如果这几条SQL语句全部执行成功&#xff0c;则才对数据库进行一次更新&#xff0c;如果有一条SQL语句执行失败&#xff0c;则这几条SQL语句全部不进行执…

C#VS2022 打包成安装包

步骤参考&#xff1a;VisualStudio&#xff08;2022&#xff09;- 打包项目文件为.exe安装包_vs2022打包exe-CSDNja 步骤参考上方链接&#xff0c;不过在Application Folder文件夹中加的是\项目名称\bin\Debug\下的全部文件&#xff0c;其他地方一样。 最终生成的安装包在Deb…

书生·浦语大模型实战2

轻松玩转书生浦语大模型趣味 Demo 大模型及 InternLM 模型简介 什么是大模型 大模型通常指的是机器学习或人工智能领域中参数数量巨大、拥有庞大计算能力和参数规模的模型。这些模型利用大量数据进行训练&#xff0c;并且拥有数十亿甚至数千亿个参数。大模型的出现和发展得益…

react输入框检索树形(tree)结构

input搜索框搜索树形子级内容1. input框输入搜索内容2. 获取tree结构数据3. 与tree匹配输入的内容&#xff0c;tree是多维数组&#xff0c;一级一级的对比输入的内容是否匹配&#xff0c;用forEach循环遍历数据&#xff0c;匹配不到在往下找&#xff0c;直到找到为null &#x…

浅谈安科瑞直流表在孟加拉某能源公司的应用

摘要&#xff1a;本文介绍了安科瑞直流电表在孟加拉某能源公司的应用。主要用于光伏直流柜内&#xff0c;配合分流器对汇流箱的输出电流电压等进行测量&#xff0c;并采集配电现场的开关信号&#xff0c;装置带有RS485接口可以把测量和采集的数据和设备状态上传。 Abstract: T…

sql:定时执行存储过程(嵌套存储过程、使用游标)

BEGINDeclare FormNo nvarchar(20) --单号Declare Type nvarchar(50) --类型Declare PickedQty float -Declare OutQty float Declare 生产量 floatDeclare 已装箱数量 float Declare 已入库数量 floatDeclare 损耗数量 float Declare 退货品出库数量 intdeclare k c…

文件夹重命名方法:文件夹名称随机数字命名,提高文件管理效率的秘诀

在数字时代&#xff0c;每天都会创建、接收和存储大量的文件。那如何有效地管理和查找这些文件&#xff1f;下面云炫文件管理器用简单的方法使用随机数字给文件夹命名。掌握方法可以快速识别和分类文件&#xff0c;提高工作效率。 文件夹随机数字命名前后效果图。 文件夹名称…

【Java EE初阶八】多线程案例(计时器模型)

1. java标准库的计时器 1.1 关于计时器 计时器类似闹钟&#xff0c;有定时的功能&#xff0c;其主要是到时间就会执行某一操作&#xff0c;即可以指定时间&#xff0c;去执行某一逻辑&#xff08;某一代码&#xff09;。 1.2 计时器的简单介绍 在java标准库中&#xff0c;提供…

阿里云服务器Centos安装宝塔面板

阿里云服务器Centos安装宝塔面板 1 背景1.1 aliyun1.2 Linux 2 安装步骤2.0 环境配置2.1 安装前准备2.2 宝塔安装2.3 建站 3 centos常用命令3.1 防火墙相关 1 背景 1.1 aliyun 阿里云服务器是阿里云提供的一项云计算服务&#xff0c;它能够帮助用户快速搭建网站、应用和服务&…

苍穹外卖Day01——总结1

总结1 1. 软件开发整体介绍1.1 软件开发流程1.2 角色分工1.3 软件环境 2. 苍穹外卖项目介绍2.1 项目介绍2.2 技术选项 3. Swagger4. 补充内容&#xff08;待解决...&#xff09; 1. 软件开发整体介绍 1.1 软件开发流程 1.2 角色分工 从角色分工里面就可以查看自己以后从事哪一…

寄10公斤包裹哪个快递便宜(寄快递哪个比较便宜)

如今&#xff0c;随着互联网的发展&#xff0c;越来越多的人选择网上购物&#xff0c;这支撑了许多物流公司不断地向前发展。所以快递行业的前景还是很光明的。现在当天寄出最晚第二天就能收到。但是快递公司那么多&#xff0c;每个公司的特色和收费都有差异。怎样才能选择合适…

windows通过ssh连接Liunx服务器并实现上传下载文件

连接ssh 输入&#xff1a;ssh空格用户名ip地址&#xff0c;然后按Enter 有可能出现下图提示&#xff0c;输入yes 回车即可 输入 password &#xff0c;注意密码是不显示的&#xff0c;输入完&#xff0c;再按回车就行了 以上是端口默认22情况下ssh连接&#xff0c;有些公司它…