1. 程式人生 > 實用技巧 >990. 等式方程的可滿足性 - medium

990. 等式方程的可滿足性 - medium

給定一個由表示變數之間關係的字串方程組成的陣列,每個字串方程 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;
    }
}