Two strings X and Y are similar if we can swap two letters (in different positions) of X, so that it equals Y.

For example, "tars" and "rats" are similar (swapping at positions 0 and 2), and "rats"and "arts" are similar, but "star" is not similar to "tars""rats", or "arts".

Together, these form two connected groups by similarity: {"tars", "rats", "arts"} and {"star"}.  Notice that "tars" and "arts" are in the same group even though they are not similar.  Formally, each group is such that a word is in the group if and only if it is similar to at least one other word in the group.

We are given a list A of strings.  Every string in A is an anagram of every other string in A.  How many groups are there?

Example 1:

Input: ["tars","rats","arts","star"]
Output: 2
分析:
因为这个是找group,所以容易联想到用union-find.这里我们在确定谁是root的时候,总是挑index大的,这样才能把不同的groups合并成一个group.
 1 public class Solution {
 2     public int numSimilarGroups(String[] A) {
 3         int[] roots = new int[A.length];
 4         for (int i = 0; i < A.length; i++) {
 5             roots[i] = i;
 6         }
 7         for (int i = 1; i < A.length; i++) {
 8             for (int j = 0; j < i; j++) {
 9                 if (similar(A[i], A[j])) {
10                     roots[find(roots, j)] = i;
11                 }
12             }
13         }
14         int result = 0;
15         for (int i = 0; i < roots.length; i++) {
16             if (roots[i] == i) {
17                 result++;
18             }
19         }
20         return result;
21     }
22     private int find(int[] roots, int id) {
23         while (roots[id] != id) {
24             roots[id] = roots[roots[id]]; // path compression
25             id = roots[id];
26         }
27         return id;
28     }
29     private boolean similar(String a, String b) {
30         int res = 0, i = 0;
31         boolean consecutive = false;
32         while (res <= 2 && i < a.length()){
33             if (a.charAt(i) != b.charAt(i)) {
34                 res++;
35             }
36             if (i > 1 && a.charAt(i) == a.charAt(i - 1)) {
37                 consecutive = true;
38             }
39             i++;
40         }
41         return res == 2 || res == 0 && consecutive;
42     }
43 }