题目描述

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

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

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

思路

这道题可以用并查集解决,当多个字母相互之间有相等关系,那么可以认为他们是在同一个集合下的,因此在一个集合下的两个元素,我们可以认为是相等的,否则就是不等的。

那么我们可以创建一个字符集,遍历这个字符串数组,将他们所有相等的拿出来(字符串的下标1对应的元素为‘=’),然后将第一个元素(字符串的下标0)和第二个元素(字符串的下标3)在并查集中相关。

然后在遍历一次字符串数组,将其中所有不相等的拿出来(字符串的下标1对应的元素为‘!’),然后判断第一个元素(字符串的下标0)和第二个元素(字符串的下标3)是否属于同一个集合,如果属于说明是对的,否则直接返回false

需要注意的是,由于我们存储的是所有小写字母之间的关系,所以并查集的大小为26即可,而我们的数组是从0下标开始的。所以我们要想节省空间,应该将每个字母存储在字母的ascii 减 字符‘a’的ascii,否则会越界

有关并查集的知识可以看我的博客:Java——并查集

具体代码

class Solution {
    public boolean equationsPossible(String[] equations) {
        MyUnionFindSet ufs = new MyUnionFindSet(26);
        for(int i = 0; i < equations.length; i++){
            if(equations[i].charAt(1) == '='){
                ufs.union(equations[i].charAt(0) - 'a',equations[i].charAt(3) - 'a');
            }
        }
        for(int i = 0; i < equations.length; i++){
            if(equations[i].charAt(1) == '!'){
                if(ufs.isSameUnionFindSet(equations[i].charAt(0) - 'a'
                    ,equations[i].charAt(3) - 'a')){
                        return false;
                    }
            }
        }
        return true;
    }
}
class MyUnionFindSet {
    public int[] elem;
    public int usedSize;

    public MyUnionFindSet(int n){
        this.elem = new int[n];
        Arrays.fill(elem, -1);//初始化数组全为-1
    }

    /**
     * 查询x1和x2是否在同一个集合中
     * @param x1
     * @param x2
     * @return
     */
    public boolean isSameUnionFindSet(int x1, int x2){
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);

        if(index1 == index2){
            return true;
        }
        return false;
    }

    /**
     * 查找x下标数据的根节点
     * @param x
     * @return 根节点的下标
     */
    public int findRoot(int x){
        if(x < 0){
            throw new ArrayIndexOutOfBoundsException("下标不能是负数");
        }

        while(elem[x] >= 0){
            x = elem[x];
        }
        return x;
    }

    /**
     * 合并x1,x2所在的两个集合
     * @param x1
     * @param x2
     */
    public void union(int x1, int x2){
       int index1 = findRoot(x1);
       int index2 = findRoot(x2);

       if(index1 == index2){
           System.out.println("x1和x2已经在同一个集合中了");
           return;
       }

       elem[index1] = elem[index1] + elem[index2];
       elem[index2] = index1;
    }

    public int getCount(){
        int count = 0;
        for (int x:elem) {
            if(x < 0){
                count++;
            }
        }
        return count;
    }

    public void print(){
        for (int x:elem) {
            System.out.print(x + " ");
        }
        System.out.println();
    }
}