leetcode 399-除法求值

在这里插入图片描述

法一:并查集

分析示例1:

  • a / b = 2.0 a/ b = 2.0 a/b=2.0,说明 a = 2 b a=2b a=2b a a a b b b在同一个集合中
  • b / c = 3.0 b/c=3.0 b/c=3.0,说明 b = 3 c b=3c b=3c b b b c c c在同一个集合中

a / c a/c a/c,可以把 a = 2 b , b = 3 c a=2b,b=3c a=2b,b=3c 依次代入,得到 a / c = 2 b c = 2 ⋅ 3 c c = 6.0 a/c=\frac{2b}{c}=\frac{2·3c}{c}=6.0 a/c=c2b=c23c=6.0

b / a b/a b/a,可以根据 a = 2 b a=2b a=2b 知道 b / a = 0.5 b/a=0.5 b/a=0.5,也可以把 b b b a a a 都转换成 c c c 的倍数, b / a = b 2 b = 3 c 6 c = 0.5 b/a=\frac{b}{2b}=\frac{3c}{6c}=0.5 b/a=2bb=6c3c=0.5

我们计算了两个结果,不难知道:可以将题目给出的 equations 中的两个变量所在集合进行**「合并」**,同在一个集合中的两个变量就可以通过某种方式计算出它们的比值。具体来说,可以把不同的变量的比值转换成相同变量的比值,然后再计算转换成相同变量以后的系数的比值,即为结果。统一了比较的标准,可以以 O ( 1 ) O(1) O(1) 的时间复杂度来完成计算。

如果两个变量不在一个集合中,返回 − 1.0 -1.0 1.0。并且根据题目的意思,如果两个变量中 至少有一个 变量没有出现在所有 equations 出现的字符集合中,也返回 − 1.0 −1.0 1.0

构建有向图

通过例1的分析,题目给出的 equationsvalues 可以表示成一个图,equations 中出现的变量就是图的顶点,「分子」与「分母」的比值可以表示成一个有向关系(因为「分子」和「分母」是有序的,不可以对换),并且这个图是一个带权图,values 就是对应的有向边的权值。

例 1 中给出的 equationsvalues 表示的「图形表示」、「数学表示」和「代码表示」如下表所示。

  • 其中 parent[a] = b 表示:结点 a 的(直接)父亲结点是 b
  • weight[a] = 2.0,即 weight[a] 表示结点 a 到它的 直接父亲结点 的有向边的权重
img

如何统一变量?

通过例1的分析,可以把 queries 中的不同变量转换成同一个变量,这样在计算 queries 的时候就可以用 O ( 1 ) O(1) O(1) 的时间复杂度计算出结果,在「并查集」的一个优化技巧中,「路径压缩」就恰好符合了这样的应用场景。

如下图所示:路径压缩前后,并查集所表示的两棵树形结构等价,路径压缩以后的树的高度为 2,查询性能最好。

image.png

由于有「路径压缩」的优化,两个在一个连通分量中的不同变量,它们分别到根节点的权值的比值就是要求的结果。

如何在「路径压缩」中维护权值变化?

如下图所示,在结点a 执行一次「查询」操作。路径压缩会先一层一层向上先找到根结点 d,然后依次把 cba 的父节点指向根节点 d

  • c 的父节点已经是根节点了,它的权值不用更改。
  • b 的父节点要修改成根节点,它的权值就是从当前节点到根节点经过的所有有向边的权值的乘积。
  • a 的父节点也要修改成根节点,但没必要把三条有向边的权值乘起来,可以直接用更新后的 bd 的权值乘以 ab 的权值。
image.png

如何在「合并」操作中维护权值的变化?

「合并」操作基于这样一个前提:将要合并的两棵树的高度最多为2,就是两棵树都必须要经过「路径压缩」。

例如:已知 a / b = 3.0 , d / c = 4.0 , a / d = 6.0 a/b=3.0,\ d/c=4.0,\ a/d=6.0 a/b=3.0, d/c=4.0, a/d=6.0,现在合并节点 ad 所在的集合,其实就是把 a 的根节点 b 指向 d 的根节点 c,那么如何计算 b 指向 c 的这条有向边的权重呢?

根据 a 经过 b 可以到达 ca 经过 d 也可以到达 c,因此两条路径上的有向边的权值的乘积必定相等。因此根据等式可求得 b / c = a d ⋅ d c a b b/c=\frac{\frac{a}{d}·\frac{d}{c}}{\frac{a}{b}} b/c=badacd

image.png

一个小细节

在合并以后,产生了一棵高度为 3 的树,那么我们在执行查询的时候,例如下图展示的绿色结点和黄色结点,绿色结点并不直接指向根结点,在计算这两个变量的比值的时候,计算边的权值的比值得到的结果是不对的。

image.png

但其实不用担心这个问题,并查集的「查询」操作会执行「路径压缩」,所以真正在计算两个变量的权值的时候,绿色结点已经指向了根结点,和黄色结点的根结点相同。因此可以用它们指向根结点的有向边的权值的比值作为两个变量的比值。

image.png

我们通过这个细节向大家强调:一边查询一边修改结点指向是并查集的特色

代码

#include <vector>
#include <unordered_map>
#include <string>
using namespace std;class UnionFind{										//并查集类
private:vector<int> parent;vector<double> weight;      						//指向父节点的权重public:UnionFind(int n){        							//初始化,节点指向自己,初始权重为1.0parent = vector<int>(n);weight = vector<double>(n);for(int i = 0; i < n; i++){parent[i] = i;weight[i] = 1.0;}}int find(int x){                                	//带路径压缩的查找if(x != parent[x]){				 				//x节点不为根节点int origin = parent[x];						//记录父节点parent[x] = find(parent[x]);				//递归向上查找父节点weight[x] *= weight[origin];				//将路径上的权重相乘}return parent[x];}void unite(int x, int y, double value){				//合并int rootX = find(x), rootY = find(y);			//查找过程中已经进行过路径压缩if(rootX == rootY)								//若在同一集合,直接返回return;parent[rootX] = rootY;							//合并操作weight[rootX] = weight[y] * value / weight[x];	//value=a/d,weight[y]=d/c,weight[x]=a/b}double isConnected(int x, int y){					//计算x/y的结果int rootX = find(x);int rootY = find(y);if(rootX == rootY)								//若为同一集合,则直接相除即为结果return weight[x] / weight[y];else											//若不为同一集合,说明问题中有未知变量return -1.0;}
};class Solution{
public:vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {int equationsSize = equations.size();UnionFind unionFind(2 * equationsSize);//第一步:预处理,将变量的值转换为数字(并查集),使得并查集的底层使用数组实现,方便编码unordered_map<string, int> hashMap(2 * equationsSize);int id = 0;for(int i = 0; i < equationsSize; i++){string var1 = equations[i][0];string var2 = equations[i][1];if(hashMap.count(var1) == 0){hashMap[var1] = id++;}if(hashMap.count(var2) == 0){hashMap[var2] = id++;}unionFind.unite(hashMap[var1], hashMap[var2], values[i]);	//将所有集合合并 var1/var2}//第二步:查询int queriesSize = queries.size();vector<double> res(queriesSize, -1.0);							//存储结果for(int i = 0; i < queriesSize; i++){string var1 = queries[i][0];string var2 = queries[i][1];if(hashMap.count(var1) && hashMap.count(var2)){				//变量在条件中出现,计算结果int id1 = hashMap[var1];int id2 = hashMap[var2];res[i] = unionFind.isConnected(id1, id2);}}return res;}
};

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

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

相关文章

24届近5年重庆邮电大学自动化考研院校分析

今天给大家带来的是重庆邮电大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、重庆邮电大学 学校简介 重庆邮电大学简称"重邮"&#xff0c;坐落于直辖市-重庆市&#xff0c;入选国家"中西部高校基础能力建设工程”、国家“卓越工程师教育培养计划…

c51单片机16个按键密码锁源代码(富proteus电路图)

注意了&#xff1a;这个代码你是没法直接运行的&#xff0c;但是如果你看得懂&#xff0c;随便改一改不超过1分钟就可以用 #include "reg51.h" #include "myheader.h" void displayNumber(unsigned char num) {if(num1){P10XFF;P10P11P14P15P160;}else if…

PyCharm新手入门指南

安装好Pycharm后&#xff0c;就可以开始编写第一个函数&#xff1a;Hello World啦~我们就先来学习一些基本的操作&#xff0c;主要包含新建Python文件&#xff0c;运行代码&#xff0c;查看结果等等。 文章主要包含五个部分&#xff1a; 一、界面介绍 主要分为菜单栏、项目目录…

osi模型

OSI 模型&#xff08;Open Systems Interconnection model&#xff09;是一个用于计算机网络体系结构的参考模型&#xff0c;由国际标准化组织&#xff08;ISO&#xff09;在 1984 年制定&#xff0c;旨在定义不同层次上的通信协议&#xff0c;以促进不同厂商的设备在网络上进行…

JQuery——动画效果

jQuery 提供了多种动画效果&#xff0c;可以让你在网页中添加平滑的过渡和动态效果。以下是一些常见的 jQuery 动画效果及其用法&#xff1a; 1. 隐藏和显示&#xff1a; 通过调用 .hide() 和 .show() 方法可以实现元素的渐隐和渐现效果。 $(#myElement).hide(); // 隐藏元素…

开发工具Eclipse的使用之导入项目(import)

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Eclipse使用的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.导读 二.详细操作步骤 1.右击项…

吐血整理,Python接口自动化测试-接口关联依赖处理(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 场景说明 在面试…

cpolar的基础使用方法

如何使用cpolar内网穿透&#xff1f; 文章目录 如何使用cpolar内网穿透&#xff1f;前言1. 在群辉NAS系统下安装cpolar套件2. 管理隧道列表3. 创建固定数据隧道 前言 群晖作为大容量存储系统&#xff0c;既可以作为个人的私有存储设备&#xff0c;也可以放在小型企业中作为数据…

创建两个线程,其中一个线程读取文件中的数据,另外一个线程将读取到的内容打印到终端上,类似实现cat一个文件。 cat数据完毕后,要结束两个线程。

#include <stdio.h> #include <pthread.h>#define BUFFER_SIZE 99999 //足够大// 全局共享的数据缓冲区 char buffer[BUFFER_SIZE]; int buffer_length 0;// 锁和条件变量用于线程同步 pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond …

vue3 Hooks 封装loading使用

vue3 Hooks 封装loading使用 个人理解&#xff1a;Hooks 就是 钩子 的意思&#xff0c;在特定时机执行的函数 之前不理解Hooks和自定义封装的utils函数有什么区别&#xff0c;它们都是函数&#xff0c;逐步理解到utils函数没有vue里面的响应式api&#xff0c;而自定义Hooks可…

基于微信小程序的传染病酒店隔离平台设计与实现(Java+spring boot+MySQL+微信小程序)

获取源码或者论文请私信博主 演示视频&#xff1a; 基于微信小程序的传染病酒店隔离平台设计与实现&#xff08;Javaspring bootMySQL微信小程序&#xff09; 使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 微信小程序 后端&#xff1a;…

回归决策树模拟sin函数

# -*-coding:utf-8-*- import numpy as np from sklearn import tree import matplotlib.pyplot as pltplt.switch_backend("TkAgg") # 创建了一个随机数生成器对象 rng rngnp.random.RandomState(1) print("rng",rng) #5*rng.rand(80,1)生成一个80行、1列…

Go语言删除文本文件中的指定行

GO语言删除文本文件中的指定行 1. 思路2. 处理文件3. 处理后的文本文件 1. 思路 假设现在有一个文本文件&#xff0c;我们需要删除文件中乱码的行。我们可以使用go的os库来处理文件&#xff0c;遍历整个文件然后将除过乱码的行写入一个新文件&#xff0c;以此来实现我们的需求…

clion run qt 问题汇总

一、Error copying file “D:/soft/QT/5.15.2/mingw81_64/bin/Qt5Cored.dll” to “D:/work/Ccode/qtproject/cmake-build-debug-qtmingw”.报错 查看路径下确实没有Qt5Cored.dll&#xff0c;只有Qt5Core.dll 注释掉cmakelist中的这三行 重新执行后成功 二、使用CLion编辑u…

【学习】若依源码(前后端分离版)之 “ 分页以及查询的功能实现”

大型纪录片&#xff1a;学习若依源码&#xff08;前后端分离版&#xff09;之 “ 分页以及查询的功能实现” 前端部分后端部分结语 包括代码生成也好&#xff0c;最原始的系统也好&#xff0c;若依里每个页面只要有数据&#xff0c;基本上就有分页的功能&#xff0c;所以理解分…

强化学习基础

强化学习 策略网络输入状态s&#xff0c;输出动作a的概率分布如下&#xff1a; π ( a ∣ s ) \pi(a|s) π(a∣s) 多次训练轨迹如下 r表示回报横轴为T, 1个回合的步骤数纵轴为N, 回合数&#xff0c;1行代表1条轨迹&#xff0c;符合概率分布P [ s 11 a 11 r 11 … … s 1 t …

机器学习实战2决策树算法

文章目录 决策树算法核心是要解决两个的关键问题sklearn中的决策树模型sklearn建模步骤分类树Criterionrandom_state && splitter剪枝参数max_depthmin_samples_leaf&&min_samples_splitmax_features&&min_impurity_decrease确认最优剪枝参数目标权重参…

VR全景智慧文旅,用科技助力旅游业振兴

引言&#xff1a; 近年来&#xff0c;科技的迅猛发展将我们带入一个全新的数字化时代&#xff0c;而虚拟现实&#xff08;Virtual Reality&#xff0c;简称VR&#xff09;技术则以其令人惊叹的全新方式&#xff0c;影响着各个领域。其中&#xff0c;旅游业作为人们探索世界、体…

Camunda 7.x 系列【12】创建流程引擎

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 2.7.9 本系列Camunda 版本 7.19.0 源码地址:https://gitee.com/pearl-organization/camunda-study-demo 文章目录 1. ProcessEngine2. 创建流程引擎2.1 Java API2.2 XML 配置2.3 Spring2.4 Spring Boot1. Pr…

系统架构设计师笔记第35期:表现层框架设计

表现层框架设计是指在软件系统中&#xff0c;将用户界面&#xff08;UI&#xff09;和用户交互逻辑与后端业务逻辑分离&#xff0c;使用特定的框架来组织和管理表现层的功能和结构。下面是表现层框架设计的一般步骤和常用技术&#xff1a; 确定需求和功能&#xff1a;首先&…