package LeetCode_839
import java.util.*
import kotlin.collections.HashSet
/**
* 839. Similar String Groups
* https://leetcode.com/problems/similar-string-groups/
* Two strings X and Y are similar if we can swap two letters (in different positions) of X, so that it equals Y.
* Also two strings X and Y are similar if they are equal.
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. 1 <= strs.length <= 100
2. 1 <= strs[i].length <= 1000
3. sum(strs[i].length) <= 2 * 10^4
4. strs[i] consists of lowercase letters only.
5. All words in strs have the same length and are anagrams of each other.
* */
class Solution {
/*
* solution: BFS, do bfs for each string to check current and next if similar,
* Time:O(n^2*l), l is length of str, Space:O(n),
* */
fun numSimilarGroups(strs: Array<String>): Int {
if (strs.size < 2) {
return strs.size
}
var group = 0
val visited = HashSet<String>()
val queue = LinkedList<String>()
for (str in strs) {
if (visited.contains(str)) {
continue
}
visited.add(str)
queue.offer(str)
group++
while (queue.isNotEmpty()) {
val cur = queue.poll()
//cur string compare with next string
for (item in strs) {
if (visited.contains(item)) {
continue
}
var diff = 0
//if the number of different char equals to 2, is similar;
//all word have the same length
for (i in cur.indices) {
if (cur[i] != item[i]) {
diff++
}
}
//put similar string into queue to check next level
if (diff == 2) {
visited.add(item)
queue.offer(item)
}
}
}
}
return group
}
}