Description
Two strings, X
and Y
, are considered similar if either they are identical or we can make them equivalent by swapping at most two letters (in distinct positions) within the string X
.
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 strs
of strings where every string in strs
is an anagram of every other string in strs
. How many groups are there?
Β
Example 1:
Input: strs = ["tars","rats","arts","star"] Output: 2
Example 2:
Input: strs = ["omv","ovm"] Output: 1
Β
Constraints:
1 <= strs.length <= 300
1 <= strs[i].length <= 300
strs[i]
consists of lowercase letters only.- All words in
strs
have the same length and are anagrams of each other.
Solution
Python3
class UnionFind:
def __init__(self, N):
self._parent = list(range(N))
self._size = [1] * N
self.component_count = N
def union(self, a, b):
a, b = self.find(a), self.find(b)
if a == b:
return
if self._size[a] < self._size[b]:
a, b = b, a
self._parent[b] = a
self._size[a] += self._size[b]
self.component_count -= 1
def find(self, x):
while self._parent[x] != x:
self._parent[x] = self._parent[self._parent[x]]
x = self._parent[x]
return x
class Solution:
def numSimilarGroups(self, strs: List[str]) -> int:
N = len(strs)
uf = UnionFind(N)
for i in range(N):
for j in range(i + 1, N):
if sum(a != b for a, b in zip(strs[i], strs[j])) in [0, 2]:
uf.union(i, j)
return uf.component_count