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

70 阅读2分钟

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

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

示例 1:

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

示例 2:

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

示例 3:

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

思路

==即建立两个变量的关系,!=即使认为两个变量没有关系,遍历所有==建立并查集,然后遍历!=利用isConnect判断是否不在一个连通分量中。本实现用了路径压缩,树高小的合并到树高高的里,类似平衡树思想,避免退化成链表

class Solution {
    public boolean equationsPossible(String[] equations) {
        //==即使建立两个变量的关系,!=即使破坏两个变量的关系,最终如果联通为一个联通量即返回true
        //等价替换一下,遍历所有等于的公式建立并查集,然后遍历!=看是否属于两个连通分量,
        Set<Character> nodes = new HashSet<>();
        List<String> equals = new ArrayList<>();
        List<String> nonEquals = new ArrayList<>();
        UnionFind<Character> unionFind = new UnionFind<>();
        for (String e : equations) {
            unionFind.add(e.charAt(0));
            unionFind.add(e.charAt(3));
            if (e.charAt(1) == '!'){
                nonEquals.add(e);
            }else{
                equals.add(e);
            }
        }
        int count = unionFind.getCount();
        for (int i = 0; i < equals.size(); i++) {
            unionFind.union(equals.get(i).charAt(0), equals.get(i).charAt(3));
        }
        for (int i = 0; i < nonEquals.size(); i++) {
            if(unionFind.isConnect(nonEquals.get(i).charAt(0), nonEquals.get(i).charAt(3))){
                return false;
            }
        }
        return true;
    }
    public class UnionFind<T>{
        Map<T, T> parents;
        Map<T, Integer> rank;
        int count;

        public UnionFind(){
            parents = new HashMap<>();
            rank = new HashMap<>();
        }

        public int getCount(){
            return count;
        }
        // 初始化
        public void add(T element){
            if (!parents.containsKey(element)) {
                parents.put(element, element); // 每个元素的父节点初始化为自己
                rank.put(element, 1);         // 初始秩为0
                count++;                      // 新增一个元素即增加一个联通分量
            }
        }

        //返回根节点
        public T find(T element){
            if (!parents.containsKey(element)){
                return null;
            }
            while (!parents.get(element).equals(element)){
                element = parents.get(element);
            }
            return element;
        }

        public boolean isConnect(T element1, T element2){
            return find(element1).equals(find(element2));
        }

        public void union(T element1, T element2){
            T t1 = find(element1);
            T t2 = find(element2);

            if (t1.equals(t2)){
                return;
            }

            if (rank.get(t1).equals(rank.get(t2))){
                parents.put(t1, t2);
                rank.put(t2, rank.get(t2) + 1);
            }else if (rank.get(t1).compareTo(rank.get(t2)) < 0){
                parents.put(t1, t2);
            }else{
                parents.put(t2, t1);
            }
            count--;
        }
    }

}