[路飞]_等式方程的可满足性

95 阅读3分钟

「这是我参与2022首次更文挑战的第31天,活动详情查看:2022首次更文挑战

leetcode-990 等式方程的可满足性

题目介绍

给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:"a==b" 或 "a!=b"。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。

只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false

示例1

输入:["a==b","b!=a"]
输出:false
解释:如果我们指定,a = 1 且 b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。

示例2

输入: ["b==a","a==b"]
输出: true
解释: 我们可以指定 a = 1 且 b = 1 以满足满足这两个方程。

示例3

输入: ["a==b","b==c","a==c"]
输出: true

示例4

输入: ["a==b","b!=c","c==a"]
输出: false

示例5

输入: ["c==c","b==d","x!=z"]
输出: true

提示:

  • 1 <= equations.length <= 500
  • equations[i].length == 4
  • equations[i][0] 和 equations[i][3] 是小写字母
  • equations[i][1] 要么是 '=',要么是 '!'
  • equations[i][2] 是 '='

解题思路

'=' 具有传递性,如果 a == b 并且 b == c,那么 a == c。这意味着相等的变量会形成一个集合,在这个集合中的所有变量都是彼此相等的,那么不在这个集合中的变量就和这个集合中的任意一个变量都不相等,因此可以判断如果题目所给出的 != 两边的变量是在同一个集合中的,那么就可以判定题目给出的方程之间有矛盾,无法成立。

解题步骤

  1. 创建一个大小为 26(提示说明变量都是小写字母表示,小写字母为26个) 的并查集
  2. 先遍历数组中 == 的方程,将 == 两边的变量在字母表中的序号进行连接
  3. 再次遍历数组中 != 的方程,判断 != 两边的变量是否在同一个集合中,如果是,则说明不成立,如果不是,继续判断下一个 !=

解题代码

var equationsPossible = function(equations) {
    const unionSet = new UnionSet(26)
    
    for (let i = 0; i < equations.length; i++) {
        // 第一次遍历时,先跳过不等式的判断,将等式两边的变量进行连通
        if (equations[i][1] === '!') continue
        const a = equations[i][0].charCodeAt() - 'a'.charCodeAt()
        const b = equations[i][3].charCodeAt() - 'a'.charCodeAt()
        unionSet.merge(a, b)
    }
    
    for (let i = 0; i < equations.length; i++) {
        // 第二次遍历时,只判断不等式两边的变量,因此跳过等式的判断
        if (equations[i][1] === '=') continue
        const a = equations[i][0].charCodeAt() - 'a'.charCodeAt()
        const b = equations[i][3].charCodeAt() - 'a'.charCodeAt()
        // 如果不等式两边的变量属于同一个集合,说明表达式不成立
        if (unionSet.find(a) === unionSet.find(b)) return false
    }
    
    // 到了这一步,说明题目中所给的等式和不等式都成立
    return true
};

// 并查集
class UnionSet {
    constructor(n) {
        this.fa = []
        this.size = []
        for (let i = 0; i < n; i++) {
            this.fa[i] = i
            this.size[i] = 1
        }
    }

    find(v) {
        if (this.fa[v] === v) return v
        const root = this.find(this.fa[v])
        this.fa[v] = root
        return root
    }

    merge(a, b) {
        const ra = this.find(a), rb = this.find(b)
        if(ra === rb) return
        if (this.size[ra] < this.size[rb]) {
            this.fa[ra] = rb
            this.size[rb] += this.size[ra]
        } else {
            this.fa[rb] = ra
            this.size[ra] += this.size[rb]
        }
    }
}