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] 是 '='

思路:

  • 并查集
  • 利用树的结构,初始化时,每一个节点都是独立的,其自身指向自身,因为这里都是小写字符,则运用长度为 26 的数组,数组中的下标,表示节点,而数组中的值,表示下标 n 的父节点 parent[n]当 n == parent[n] 时,表明节点 n 的父节点也是 n,说明其就是根节点
  • 对于等式的处理,将等式两边的字符,连通在一起,连通的时候要注意,要找到两边的根节点,将根节点连通在一起
  • 要找到一个节点 n1的根节点,将其根节点挂载到另一个节点 n2 的根节点中,不能将自身 n1 直接挂载到 n2 的根节点中;
  • 比如: a == b 此时又有 a == c (我用的是固定将第一个节点挂载到第二个节点中)则要将 a 的根节点 b ,挂载到 c 中,而不是直接将 a 挂载到 c 中,否则,判断 b==c 时出错,第一次提交时犯了这个错误
  • 对于不等式的处理,如果发现不等式两边,是连通的,也就是说,有共同的根节点,则不满足不等式的定义,返回 false.
  • 如果所有的不等式都满足,则返回 true.

class Solution {
    public boolean equationsPossible(String[] equations) {
        int[] parent = new int[26];
        for(int i = 0; i < 26; i++){
            parent[i] = i; //让每一个节点的根节点指向自身
        }
        for(String s : equations){
            if(s.charAt(1) == '='){
                int n1 = s.charAt(0) - 'a';
                int n2 = s.charAt(3) - 'a';
                union(parent, n1, n2); //连通起来
            }
        }
        for(String s : equations){
            if(s.charAt(1) == '!'){ //对不相等的等式,判断两边是否是连通的
                int n1 = s.charAt(0) - 'a';
                int n2 = s.charAt(3) - 'a'; //如果连通了,则违反了不相等的规则,返回 false
                if(findRoot(parent, n1) == findRoot(parent, n2)) return false;
            }
        }
        return true; //对于不等式,都满足条件,则返回 true
    }
    public void union(int[] parent, int n1, int n2){ //将 n1挂载连通到 n2 中
        //parent[n1] = findRoot(parent, n2); // 错误,将自己挂载到 n2根节点
        parent[findRoot(parent,n1)] = findRoot(parent,n2); //正确,将自己根节点挂载
    }
    public int findRoot(int[] parent, int n){ //寻找每一个节点的根节点
        while(parent[n] != n){ //根节点满足:自身指向自身,如果不是,说明不是根节点
            n = parent[n];
        }
        return n;
    }
}
原文地址:https://www.cnblogs.com/luo-c/p/13974287.html