leetcode 399-除法求值

news2024/9/22 19:46:42

在这里插入图片描述

法一:并查集

分析示例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.0
        parent = 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.coloradmin.cn/o/855404.html

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

相关文章

C++ Primer(第5版) 全书重点学习笔记

目录 第12章 动态内存 12.1 动态内存与智能指针 12.1.6 weak_ptr 12.2 动态数组 12.2.1 new和数组 12.2.2 allocator类 第12章 动态内存 12.1 动态内存与智能指针 12.1.6 weak_ptr weak_ptr是一种不控制所指向对象生存期的智能指针&#xff0c;它指向由一个shared_pt…

微信小程序申请步骤

微信公众平台链接&#xff1a;https://mp.weixin.qq.com/ 1、进到微信公众平台&#xff0c;点一下“点击注册”&#xff0c;挑选账号申请种类“小程序”&#xff0c;填好微信小程序用户信息&#xff0c;包含电子邮箱、登陆密码等。 2、微信公众平台会发送一封电子邮件&#xf…

监控Elasticsearch的关键指标

Elasticsearch 的核心职能就是对外提供搜索服务&#xff0c;所以搜索请求的吞吐和延迟是非常关键的&#xff0c;搜索是靠底层的索引实现的&#xff0c;所以索引的性能指标也非常关键&#xff0c;Elasticsearch 由一个或多个节点组成集群&#xff0c;集群自身是否健康也是需要我…

Linux网络服务之SSH

SSH 一、SSH概述1.1 定义1.2 SSH的优点1.3 OpenSSH1.3.1 定义1.3.2 SSH服务器-----sshd 二、SSH原理三、SSH登录方式3.1 方式一3.2 方式二3.3 方式三&#xff1a;跳板连接3.3.1 跳板连接概述3.3.2 具体配置 3.4 方式四&#xff1a;远程控制 四、服务端配置4.1 系统安全架构----…

企业内部wiki,让知识不再流于表面,让企业管理更加高效

企业内部wiki是一种基于wiki技术的内部知识管理平台&#xff0c;通常由企业自行搭建和维护&#xff0c;用于收集和整理企业内部的知识、经验和流程等信息。它可以帮助企业实现知识共享、协作和沟通&#xff0c;提高工作效率和团队协作能力。企业内部wiki还可以作为企业文化建设…

Python Pandas 使用示例

文章目录 使用Boolean 选择rows读取Excel表格里指定的sheet, 并跳过起始n行删除只有一个元素的行删除重复的合并多个csv文件到excel表格中获取csv文件的数据 使用Boolean 选择rows import pandas as pd# Sample DataFrame data {Name: [John, Alice, Bob, Emily],Age: [25, 3…

Segment Anything(SAM) 计算过程

给定输入图像 I ∈ R 3 H W I \in R^{3 \times H \times W} I∈R3HW。给定需要的prompts&#xff1a; M ∈ R 1 H W M \in R^{1 \times H \times W} M∈R1HW&#xff0c;代表图片的前背景信息。 P ∈ R N 2 P \in R^{N \times 2} P∈RN2&#xff0c;其中 N N N 是点的个数…

SpringBoot 底层机制分析【Tomcat 启动+Spring 容器初始化+Tomcat 如何关联Spring 容器】【下】

&#x1f600;前言 本篇博文是关于SpringBoot 底层机制分析实现&#xff0c;希望能够帮助你更好的了解SpringBoot &#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大…

多年软件测试面试经验,给正在面试工作的一些建议

工作8年多&#xff0c;测试管理经验4年左右&#xff0c;电话面试现场面试了很多测试工程师候选人员&#xff0c;总结下面试过程中我经常会问到的问题和梳理下我的面试流程&#xff0c;希望对候选人员有所帮助。 1.自我介绍 自我介绍其实并不是我想了解除了简历之外的候选人的…

【王树森】深度强化学习(DRL)课程笔记:P2 价值学习

Value-Based RL 试图找出能预测最优action的Q*函数 Deep Q Network(DQN) Temporal Difference(TD) Learning Example 如果在只到半路DC能不能更新模型&#xff1f; TD在这种情况下也可以学习的原因 TD learning for DQN 使用TD Learning 训练 DQN Summary

oracle sql developer批量删除某个用户

随着navicate收费&#xff0c;还得破解&#xff0c;pl/sql developer配置麻烦&#xff0c;最近使用oracle sql developer来试试oracle的操作如何&#xff1b; 用着还行&#xff0c;没有卡顿现象&#xff0c; 最近要oracle sql developer批量删除某个用户下所有的表&#xff0…

springboot中消失的静态资源

springboot中消失的静态资源 问题&#xff1a;springboot项目中&#xff0c;resource/static 目录下的index.html以及template目录下 。实现WebMvcConfigurer这个接口&#xff0c;index.html就404了。 原因&#xff1a;实现了 WebMvcConfigurer 接口后&#xff0c;index.html …

网络安全的相关知识点

网络安全威胁类型&#xff1a; 1.窃听&#xff1a;广播式网络系统。 2.假冒 3.重放&#xff1a;重复一份报文或者报文的一部分&#xff0c;以便产生一个被授权的效果。 4.流量分析 5.数据完整性破坏 6.拒绝服务 7.资源的非授权使用 8.陷门和特洛伊木马&#xff1a;木马病毒有客…

Kali中AWD靶机环境搭建

Kali中AWD靶机环境搭建 1、kali安装docker2、克隆项目&#xff08;400多M&#xff0c;下载会有点久&#xff09;3、进入项目4、下载镜像5、改镜像名6、比赛环境搭建6.1 启动靶机6.2 连接裁判机&#xff0c;启动check脚本6.3 关闭环境命令 7、 靶机访问方式7.1 web界面访问7.2 s…

AMD 翻身无望,RX7000多款主流新卡出炉逗乐NVIDIA

看了今年 NVIDIA RTX 40 系中端主流级显卡&#xff0c;让咱明白了什么叫毫无诚意。 4060 核心规模不及 4090 的 19%、4060Ti 打不过 3070&#xff0c;可真是小刀划屁股开了眼。 奈何 AMD 这代 RX 7000 系显卡着实给不上压力。 旗舰 RX 7900 XTX、7900 XT 完全不敌 RTX 4090、…

go get报错

这里写目录标题 执行 go install github.com/mitchellh/goxlatest提示下面错误&#xff0c;我浏览器直接访问时能访问了&#xff0c;这个下面的提示是golang代理问题 go install: github.com/mitchellh/goxlatest: module github.com/mitchellh/gox: Get “https://proxy.golan…

职场演讲口才培训的影响研究:演讲训练项目的效果探究

题目&#xff1a;职场演讲口才培训的影响研究&#xff1a;演讲训练项目的效果探究 I. 引言 A. 话题背景和意义 在现代职场中&#xff0c;良好的演讲口才已经成为一个不可或缺的技能。随着全球化和信息技术的迅速发展&#xff0c;职场中的沟通方式和需求也发生了巨大变化。无论…

多门店小程序怎么弄

连锁多门店小程序是一种基于微信平台的应用&#xff0c;旨在为连锁企业提供线上线下一体化的服务。以下是该小程序的功能介绍&#xff1a; 1. 门店查找&#xff1a;用户可以通过小程序查找附近的连锁门店&#xff0c;根据地理位置、距离等条件进行筛选&#xff0c;并查看每个门…

MFC创建和使用OCX控件

文章目录 MFC建立OCX控件注册OCX控件与反注册使用Internet Explorer测试ocx控件OCX控件添加方法OCX控件添加事件Web使用OCX控件MFC使用OCX控件使用OCX控件调用ocx的功能函数对ocx的事件响应OCX控件调试工具tstcon32.exe加载ocx控件使用tstcon32.exe调试ocxMFC建立OCX控件 新建…

镜像网站汇总【8月9日更新】

今日最新整理&#xff1a;还是最基本原则&#xff1a; 不用注册&#xff0c; 不用登录&#xff0c; 不用魔法&#xff0c; 不用梯子&#xff0c; 必须是上来就用的镜像&#xff01; 第一个&#xff1a;可用网址汇总 网址&#xff1a;https://c.aalib.net/tool/chatgpt/ …