|
| 1 | +/** |
| 2 | + * 839. Similar String Groups |
| 3 | + * https://leetcode.com/problems/similar-string-groups/ |
| 4 | + * Difficulty: Hard |
| 5 | + * |
| 6 | + * Two strings, X and Y, are considered similar if either they are identical or we can make them |
| 7 | + * equivalent by swapping at most two letters (in distinct positions) within the string X. |
| 8 | + * |
| 9 | + * For example, "tars" and "rats" are similar (swapping at positions 0 and 2), and "rats" and |
| 10 | + * "arts" are similar, but "star" is not similar to "tars", "rats", or "arts". |
| 11 | + * |
| 12 | + * Together, these form two connected groups by similarity: {"tars", "rats", "arts"} and {"star"}. |
| 13 | + * Notice that "tars" and "arts" are in the same group even though they are not similar. Formally, |
| 14 | + * each group is such that a word is in the group if and only if it is similar to at least one |
| 15 | + * other word in the group. |
| 16 | + * |
| 17 | + * We are given a list strs of strings where every string in strs is an anagram of every other |
| 18 | + * string in strs. How many groups are there? |
| 19 | + */ |
| 20 | + |
| 21 | +/** |
| 22 | + * @param {string[]} strs |
| 23 | + * @return {number} |
| 24 | + */ |
| 25 | +var numSimilarGroups = function(strs) { |
| 26 | + const parent = Array.from({ length: strs.length }, (_, i) => i); |
| 27 | + const rank = new Array(strs.length).fill(0); |
| 28 | + |
| 29 | + for (let i = 0; i < strs.length; i++) { |
| 30 | + for (let j = i + 1; j < strs.length; j++) { |
| 31 | + if (areSimilar(strs[i], strs[j])) union(i, j); |
| 32 | + } |
| 33 | + } |
| 34 | + |
| 35 | + const groups = new Set(); |
| 36 | + for (let i = 0; i < strs.length; i++) groups.add(find(i)); |
| 37 | + |
| 38 | + return groups.size; |
| 39 | + |
| 40 | + function find(x) { |
| 41 | + if (parent[x] !== x) { |
| 42 | + parent[x] = find(parent[x]); |
| 43 | + } |
| 44 | + return parent[x]; |
| 45 | + } |
| 46 | + |
| 47 | + function union(x, y) { |
| 48 | + const rootX = find(x); |
| 49 | + const rootY = find(y); |
| 50 | + |
| 51 | + if (rootX === rootY) return; |
| 52 | + |
| 53 | + if (rank[rootX] < rank[rootY]) { |
| 54 | + parent[rootX] = rootY; |
| 55 | + } else { |
| 56 | + parent[rootY] = rootX; |
| 57 | + if (rank[rootX] === rank[rootY]) rank[rootX]++; |
| 58 | + } |
| 59 | + } |
| 60 | + |
| 61 | + function areSimilar(a, b) { |
| 62 | + if (a === b) return true; |
| 63 | + |
| 64 | + let diff = 0; |
| 65 | + for (let i = 0; i < a.length; i++) { |
| 66 | + if (a[i] !== b[i] && ++diff > 2) return false; |
| 67 | + } |
| 68 | + |
| 69 | + return diff === 2; |
| 70 | + } |
| 71 | +}; |
0 commit comments