399. 除法求值

106 阅读2分钟

题目:
给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件,其中 equations[i] = [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi = values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。

另有一些以数组 queries 表示的问题,其中 queries[j] = [Cj, Dj] 表示第 j 个问题,请你根据已知条件找出 Cj / Dj = ? 的结果作为答案。

返回 所有问题的答案 。如果存在某个无法确定的答案,则用 -1.0 替代这个答案。如果问题中出现了给定的已知条件中没有出现的字符串,也需要用 -1.0 替代这个答案。

注意: 输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况,且不存在任何矛盾的结果。

算法:
方法一:并查集(带边权)
总体思路:将a,b,表示为n * root这种形式,a/b就是weight[a]/weight[b] = n * root / m * root。如果a,b不连通则返回-1。
注意find()方法要计算权重,保证节点的权重是相对于同一个根节点。

var unionFind []int
var weight []float64
func calcEquation(equations [][]string, values []float64, queries [][]string) []float64 {
	n := len(equations)
	unionFind = make([]int, 2 * n)
	weight = make([]float64, 2 * n)
	keyMap := make(map[string]int)
	// 1.初始化unionfind
	for i := range unionFind {
		unionFind[i] = i
		weight[i] = float64(1)
	}
	id := 0
	for i := range equations {
		if _, ok := keyMap[equations[i][0]]; !ok {
			keyMap[equations[i][0]] = id
			id ++
		} 
		if _, ok := keyMap[equations[i][1]]; !ok {
			keyMap[equations[i][1]] = id
			id ++
		} 
		union(keyMap[equations[i][0]], keyMap[equations[i][1]], values[i])
	}

	// 2.查询结果
	ans := make([]float64, len(queries))
	for i := range queries {
		id1, ok1 := keyMap[queries[i][0]]
		id2, ok2 := keyMap[queries[i][1]]
		if !ok1 || !ok2 {
			ans[i] = float64(-1)
		} else {
			ans[i] = isConnect(id1, id2)
		}
	}
	return ans
}

func union(x, y int, value float64) {
	xf := find(x)
	yf := find(y)
	if xf == yf {
		return
	}
	unionFind[xf] = yf
	// 将xf的父亲设置为yf了,设置xf的权重
	// weight[x->xf] * weight[xf->yf] = weight[x->y] * weight[y->yf]   
	// weight[x] * weight[xf] = value * weight[y]
	weight[xf] = value * weight[y] / weight[x]
}

func find(x int) int {
	xf := unionFind[x]
	if xf != x {
		origin := unionFind[x]
		unionFind[x] = find(xf)
                // 查询的时候要计算权重,确保节点x已经用根节点表示了,isConnect中查询weight得到的才都是相对同一个根节点的的权重
		// x到根节点的权重 = x的权重 * x的父亲的权重
		weight[x] =  weight[x] * weight[origin]
	}
	return unionFind[x]
}

func isConnect(x, y int) float64 {
	xf := find(x)
	yf := find(y)
	// x,y不联通则返回-1
	if xf != yf {
		return float64(-1)
	}
	// 联通则x,y已经用同一个父节点表示。如x=2 * root, y=3 * root
	return weight[x] / weight[y]
}