题目
给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:a==b 或 a!=b。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。
只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false。 
代码
    private class UnionFind {
        private int[] parent;
        public UnionFind(int n) {
            parent = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
            }
        }
        // 在这里用的是隔代路径压缩,较彻底路径压缩(递归实现)而言,虽压缩不完全但性能较高
        public int find(int x) {
            while (x != parent[x]) {
                parent[x] = parent[parent[x]];
                x = parent[x];
            }
            return x;
        }
        public void union(int x, int y) {
            int rootX = find(x);
            int rootY = find(y);
            parent[rootX] = rootY;
        }
        public boolean isConnected(int x, int y) {
            return find(x) == find(y);
        }
    }
    public boolean equationsPossible(String[] equations) {
        UnionFind unionFind = new UnionFind(26);
        for (String equation : equations) {
            char[] charArr = equation.toCharArray();
            if (charArr[1] == '=') {
                int index1 = charArr[0] - 'a';
                int index2 = charArr[3] - 'a';
                unionFind.union(index1, index2);
            }
        }
        for (String equation : equations) {
            char[] charArr = equation.toCharArray();
            if (charArr[1] == '!') {
                int index1 = charArr[0] - 'a';
                int index2 = charArr[3] - 'a';
                if (unionFind.isConnected(index1, index2)) {
                    return false;
                }
            }
        }
        return true;
    } 题外话
今天做到这个题学到了一个新知识点——并查集,就做个记录总结下。
CSDN博主的一篇文章将并查集讲述的生动形象,可以前往阅览。
相关概念
- 并查集 是一种树型的数据结构,用来处理一些不交集的 合并 及 查询 问题。
 - 并查集森林 是一种将每一个集合以树表示的数据结构,其中每一个节点保存着到它父节点的引用。
 
代码实现
其中主要就是 find 和 union 两个方法。
find 方法用来寻找两个节点的根节点,如果两个节点的根节点一致,两个节点就是连通的。在寻找时可以进行路径压缩来优化查找效率。举个例子,假设原来的树内节点构成了一条线,则查找效率为 O(n),而如果在每次查找后将当前节点连接到父节点的父结点上(隔代路径压缩),或者直接将查找节点连接到根节点(彻底路径压缩)。那么经过多次的查找,当前树的深度就会变得很低,可以方便的找到当前节点所在树的根节点。
隔代路径压缩
public int find(int x) { while (x != parent[x]) { parent[x] = parent[parent[x]]; x = parent[x]; } return x; }彻底路径压缩
public int find(int x) { if (parent[x]!=x) { parent[x] = find(parent[x]); } return parent[x]; }
union 方法是用来连结两个原来不相关的树,实现也较为简单,找到两个节点所在树的根节点,将其中一个根节点指向另外一个根节点即可。
并查集的具体代码如下:
    private class UnionFind {
        private int[] parent;
        public UnionFind(int n) {
            parent = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
            }
        }
        // 在这里用的是隔代路径压缩,较彻底路径压缩(递归实现)而言,虽压缩不完全但性能较高
        public int find(int x) {
            while (x != parent[x]) {
                parent[x] = parent[parent[x]];
                x = parent[x];
            }
            return x;
        }
        public void union(int x, int y) {
            int rootX = find(x);
            int rootY = find(y);
            parent[rootX] = rootY;
        }
        public boolean isConnected(int x, int y) {
            return find(x) == find(y);
        }
    } 
京公网安备 11010502036488号