int n = equations.size(); for (int i = 0; i < n; i++) { if (variables.find(equations[i][0]) == variables.end()) { variables[equations[i][0]] = nvars++; } if (variables.find(equations[i][1]) == variables.end()) { variables[equations[i][1]] = nvars++; } }
// 对于每个点,存储其直接连接到的所有点及对应的权值 vector<vector<pair<int, double>>> edges(nvars); for (int i = 0; i < n; i++) { int va = variables[equations[i][0]], vb = variables[equations[i][1]]; edges[va].push_back(make_pair(vb, values[i])); edges[vb].push_back(make_pair(va, 1.0 / values[i])); }
vector<double> ret; for (constauto& q: queries) { double result = -1.0; if (variables.find(q[0]) != variables.end() && variables.find(q[1]) != variables.end()) { int ia = variables[q[0]], ib = variables[q[1]]; if (ia == ib) { result = 1.0; } else { queue<int> points; points.push(ia); vector<double> ratios(nvars, -1.0); ratios[ia] = 1.0;
while (!points.empty() && ratios[ib] < 0) { int x = points.front(); points.pop();
var calcEquation = function(equations, values, queries) { let nvars = 0; const variables = newMap();
const n = equations.length; for (let i = 0; i < n; i++) { if (!variables.has(equations[i][0])) { variables.set(equations[i][0], nvars++); } if (!variables.has(equations[i][1])) { variables.set(equations[i][1], nvars++); } }
// 对于每个点,存储其直接连接到的所有点及对应的权值 const edges = newArray(nvars).fill(0); for (let i = 0; i < nvars; i++) { edges[i] = []; } for (let i = 0; i < n; i++) { const va = variables.get(equations[i][0]), vb = variables.get(equations[i][1]); edges[va].push([vb, values[i]]); edges[vb].push([va, 1.0 / values[i]]); }
const queriesCount = queries.length; const ret = []; for (let i = 0; i < queriesCount; i++) { const query = queries[i]; let result = -1.0; if (variables.has(query[0]) && variables.has(query[1])) { const ia = variables.get(query[0]), ib = variables.get(query[1]); if (ia === ib) { result = 1.0; } else { const points = []; points.push(ia); const ratios = newArray(nvars).fill(-1.0); ratios[ia] = 1.0;
while (points.length && ratios[ib] < 0) { const x = points.pop(); for (const [y, val] of edges[x]) { if (ratios[y] < 0) { ratios[y] = ratios[x] * val; points.push(y); } } } result = ratios[ib]; } } ret[i] = result; } return ret; };
复杂度分析
时间复杂度:O(ML+Q\cdot(L+M)),其中 M 为边的数量,Q 为询问的数量,L 为字符串的平均长度。构建图时,需要处理 M 条边,每条边都涉及到 O(L) 的字符串比较;处理查询时,每次查询首先要进行一次 O(L) 的比较,然后至多遍历 O(M) 条边。
funccalcEquation(equations [][]string, values []float64, queries [][]string) []float64 { // 给方程组中的每个变量编号 id := map[string]int{} for _, eq := range equations { a, b := eq[0], eq[1] if _, has := id[a]; !has { id[a] = len(id) } if _, has := id[b]; !has { id[b] = len(id) } }
// 建图 graph := make([][]float64, len(id)) for i := range graph { graph[i] = make([]float64, len(id)) } for i, eq := range equations { v, w := id[eq[0]], id[eq[1]] graph[v][w] = values[i] graph[w][v] = 1 / values[i] }
// 执行 Floyd 算法 for k := range graph { for i := range graph { for j := range graph { if graph[i][k] > 0 && graph[k][j] > 0 { graph[i][j] = graph[i][k] * graph[k][j] } } } }
ans := make([]float64, len(queries)) for i, q := range queries { start, hasS := id[q[0]] end, hasE := id[q[1]] if !hasS || !hasE || graph[start][end] == 0 { ans[i] = -1 } else { ans[i] = graph[start][end] } } return ans }
classSolution { public: intfindf(vector<int>& f, vector<double>& w, int x){ if (f[x] != x) { int father = findf(f, w, f[x]); w[x] = w[x] * w[f[x]]; f[x] = father; } return f[x]; }
voidmerge(vector<int>& f, vector<double>& w, int x, int y, double val){ int fx = findf(f, w, x); int fy = findf(f, w, y); f[fx] = fy; w[fx] = val * w[y] / w[x]; }
funccalcEquation(equations [][]string, values []float64, queries [][]string) []float64 { // 给方程组中的每个变量编号 id := map[string]int{} for _, eq := range equations { a, b := eq[0], eq[1] if _, has := id[a]; !has { id[a] = len(id) } if _, has := id[b]; !has { id[b] = len(id) } }
fa := make([]int, len(id)) w := make([]float64, len(id)) for i := range fa { fa[i] = i w[i] = 1 } var find func(int)int find = func(x int)int { if fa[x] != x { f := find(fa[x]) w[x] *= w[fa[x]] fa[x] = f } return fa[x] } merge := func(from, to int, val float64) { fFrom, fTo := find(from), find(to) w[fFrom] = val * w[to] / w[from] fa[fFrom] = fTo }
for i, eq := range equations { merge(id[eq[0]], id[eq[1]], values[i]) }
ans := make([]float64, len(queries)) for i, q := range queries { start, hasS := id[q[0]] end, hasE := id[q[1]] if hasS && hasE && find(start) == find(end) { ans[i] = w[start] / w[end] } else { ans[i] = -1 } } return ans }
var calcEquation = function(equations, values, queries) { let nvars = 0; const variables = newMap();
const n = equations.length; for (let i = 0; i < n; i++) { if (!variables.has(equations[i][0])) { variables.set(equations[i][0], nvars++); } if (!variables.has(equations[i][1])) { variables.set(equations[i][1], nvars++); } } const f = newArray(nvars).fill(0).map((val, index) => index); const w = newArray(nvars).fill(1.0);
for (let i = 0; i < n; i++) { const va = variables.get(equations[i][0]), vb = variables.get(equations[i][1]); merge(f, w, va, vb, values[i]); } const queriesCount = queries.length; const ret = newArray(queriesCount).fill(0); for (let i = 0; i < queriesCount; i++) { const query = queries[i]; let result = -1.0; if (variables.has(query[0]) && variables.has(query[1])) { const ia = variables.get(query[0]), ib = variables.get(query[1]); const fa = findf(f, w, ia), fb = findf(f, w, ib); if (fa == fb) { result = w[ia] / w[ib]; } } ret[i] = result; } return ret; }