Java實現LeetCode 839. 類似字符串組 (深度優先搜索,並查集,圖)

若是咱們交換字符串 X 中的兩個不一樣位置的字母,使得它和字符串 Y 相等,那麼稱 X 和 Y 兩個字符串類似。若是這兩個字符串自己是相等的,那它們也是類似的。css

例如,"tars" 和 "rats" 是類似的 (交換 0 與 2 的位置); "rats" 和 "arts" 也是類似的,可是 "star" 不與 "tars""rats",或 "arts" 類似。node

總之,它們經過類似性造成了兩個關聯組:{"tars", "rats", "arts"} 和 {"star"}。注意,"tars" 和 "arts" 是在同一組中,即便它們並不類似。形式上,對每一個組而言,要肯定一個單詞在組中,只須要這個詞和該組中至少一個單詞類似。數組

咱們給出了一個不包含重複的字符串列表 A。列表中的每一個字符串都是 A 中其它全部字符串的一個字母異位詞。請問 A 中有多少個類似字符串組?this

 

示例:spa

輸入:["tars","rats","arts","star"]
輸出:2

 

 

提示:調試

  1. A.length <= 2000
  2. A[i].length <= 1000
  3. A.length * A[i].length <= 20000
  4. A 中的全部單詞都只包含小寫字母。
  5. A 中的全部單詞都具備相同的長度,且是彼此的字母異位詞。
  6. 此問題的判斷限制時間已經延長。

 

備註:code

      字母異位詞[anagram],一種把某個字符串的字母的位置(順序)加以改換所造成的新詞。blog

 

大意:leetcode

  咱們判斷是否類似,若是類似的話,就把他放到並查集裏面,並查集對於檢索分組狀況相對比較快字符串

  每次放到並查集裏面,確定是有一個類似的,既然有一個類似的,總組數必定-1(初始的總組數爲數組的大小)

 

 

class Solution {
    //並查集
    private int[] parent;
    //分的組數
    private int groupNum;

    public int numSimilarGroups(String[] A) {
        int n = A.length;
        groupNum=n;
        parent = new int[n];
        //並查集第一步,給每個數組都附上初始值,到時候只須要對比parent[i]==i便可瞭解是否是存在一個組
        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }
        // 預處理輸入
        int len = A[0].length();
        char[][] chars = new char[n][len];
        //這裏用char[][]是由於String相對來講會比較慢
        for (int i = 0; i < n; i++) {
            chars[i] = A[i].toCharArray();
        }
        // 枚舉每一對單詞,檢查是否類似,若類似則合併
        for (int i = 0; i < n - 1; i++) {
            for (int j = i + 1; j < n; j++) {
                if (similar(chars[i], chars[j])) {
                    //其實這裏有一個小細節,這裏是i永遠小於j(並查集的關鍵)
                    union(i, j);
                }
            }
        }
         
        return groupNum;
    }

    // 用來判斷一對單詞是否類似
    private boolean similar(char[] w1, char[] w2) {
        int diff = 0;
        int n = w1.length;
        for (int i = 0; i < n; i++) {
            //只要不相等得數量大於兩個就說明不類似
            if (w1[i] != w2[i] && ++diff > 2) {
                return false;
            }
        }
        return true;
    }
    //查找子集
    private int find(int node) {
        return parent[node] == node ? node : (parent[node] = find(parent[node]));
    }
    //並查集查找
    //node1<<node2
    private void union(int node1, int node2) {
        int root1 = find(node1);
        int root2 = find(node2);
        if (root1 == root2) {
            return;
        }
        //root1是相對root2來講比較小的(若是不理解,就本身調試看一下)
        parent[root1] = root2;
        //每當並查集鏈接一個組,總組數量-1
        this.groupNum--;
    }
}
相關文章
相關標籤/搜索