题意分析
这题一看连通关系,知道用并查集会比较好解决。只是这题复杂在不仅仅要判断连通,还要计算一个线性数值关系,所以要小改一下。
算法思路
- 先建立一个并查集类,建立parent和权值数组,parent用来找标识位--“根”,权值数组用来找倍数关系。然后必有初始编号,找父节点,合并等基础操作,此处多加个计算倍数操作
- 将元素及倍数关系放进去,这里用到了哈希映射的技巧。
- 最后查找两字符串根节点相同,则存在倍数关系,输出即可。
代码实现
class Union{
vector<int> parent;
vector<double> weight;
public:
Union(int n){
for(int i=0;i<n;i++){
parent.emplace_back(i);
weight.emplace_back(1.0);
}
}
int find(int index){
if(index==parent[index]) return index;
int origin=parent[index];
parent[index]=find(parent[index]);
weight[index]*=weight[origin];//只要乘上前一个节点倍数即可
return parent[index];
}
double isconnect(int i1,int i2){
if(find(i1)==find(i2))
return weight[i1]/weight[i2];
return -1;
}
void unite(int i1,int i2,double value){//注意参数输入是double
int rx=find(i1),ry=find(i2);
parent[rx]=ry;
weight[rx]=weight[i2]*value/weight[i1]; //该节点到根总倍数/该节点到原根的倍数=原根到现根的倍数
}
};
class Solution {
public:
vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
int equationsize=equations.size();
Union uf(2*equationsize);
unordered_map<string,int> hashmap;
int id=0;
for(int i=0;i<equationsize;i++){
auto &e=equations[i];
string a=e[0],b=e[1];
if(!hashmap.count(a)) hashmap[a]=id++;
if(!hashmap.count(b)) hashmap[b]=id++;
uf.unite(hashmap[a],hashmap[b],values[i]);
}
int queriesize=queries.size();
vector<double> res(queriesize,-1.0);
for(int i=0;i<queriesize;i++){
auto &e=queries[i];
string a=e[0],b=e[1];
if(hashmap.count(a) && hashmap.count(b)) res[i]=uf.isconnect(hashmap[a],hashmap[b]);//注意要判断在hashmap中是否存在,因为类里没判断不存在情况
}
return res;
}
};
解题总结
并查集记牢,然后父子关系怎么映射想清楚,会哈希表映射技巧这题可解。