839. 相似字符串组
题目来源:力扣(LeetCode)https://leetcode-cn.com/problems/similar-string-groups/
题目
如果交换字符串 X
中的两个不同位置的字母,使得它和字符串 Y
相等,那么称 X
和 Y
两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。
例如,"tars"
和 "rats"
是相似的 (交换 0
与 2
的位置); "rats"
和 "arts"
也是相似的,但是 "star"
不与 "tars"
,"rats"
,或 "arts"
相似。
总之,它们通过相似性形成了两个关联组:{"tars", "rats", "arts"}
和 {"star"}
。注意,"tars"
和 "arts"
是在同一组中,即使它们并不相似。形式上,对每个组而言,要确定一个字符串在组中,只需要这个词和该组中至少一个字符串相似。
给你一个字符串列表 strs
。列表中的每个字符串都是 strs
中其它所有字符串的一个字母异位词。请问 strs
中有多少个相似字符串组?
示例 1:
输入:strs = ["tars","rats","arts","star"]
输出:2
示例 2:
输入:strs = ["omv","ovm"]
输出:1
提示:
1 <= strs.length <= 100
1 <= strs[i].length <= 1000
sum(strs[i].length) <= 2 * 104
strs[i]
只包含小写字母。strs
中的所有字符串都具有相同的长度,且是彼此的字母异位词。
备注:
字母异位词(anagram),一种把某个字符串的字母的位置(顺序)加以改换所形成的新词。
解题思路
思路:并查集
先说明下,虽然本题的难度标为 困难,但是理清题意之后,就能够下手解决问题。
现在先审题,题目给定一个字符串列表 s t r s strs strs,而 s t r s strs strs 中的所有字符串都具有相同长度,且是彼此的字母异位词。
字母异位词(anagram):一种把某个字符串的字母的位置(顺序)加以改换所形成的新词。
再看下本题中的规则:
- 如果交换字符串 X X X 两个不同位置的字母,使得它与字符串 Y Y Y 相等。那么称两个字符串相似。若两个字符串本身相等,同样可认为是相似。
以示例 1 举例来说明:
输入:strs = ["tars","rats","arts","star"]
输出:2
- 其中 t a r s tars tars 与 r a t s rats rats 是相似的,因为 t a r s tars tars 交换 0 和 2 位置的字符后,与 r a t s rats rats 相等
- r a t s rats rats 与 a r t s arts arts 也是相似的, r a t s rats rats 交换 0 和 1 的位置后,与 a r t s arts arts 相等
但是这里 s t a r star star 与 t a r s 、 r a t s 、 a r t s tars、rats、arts tars、rats、arts 均不相似,因为 s t a r star star 无法通过交换两个字符,使得转换后的字符串与其他三个字符串相等。
这里就是第一个需要注意的点,通过上面的分析,判断字符串相似,只能够通过交换其中一个字符串中的两个字符后,判断两个字符串是否相等,注意这里的交换是只有一次的。
上面 s t a r star star 就是这样的情况,无论如何,都无法通过一次交换两个字符,使得转换后的字符串与其他三个字符相等。
也就是说当两个字符串中仅有两个字符对应的位置不同,其他字符均一一对应的,才能够判定两个字符串相似。
若两个字符串中的字符对应位置不同数超过 2 个,那么无论如何交换都无法使得交换后的字符串与另外的字符串相等。
题目中还给出根据相似性进行分组,示例 1 中的分组如下:
1. {"tars", "rats", "arts"}
2. {"star"}
在第一个分组中, t a r s tars tars 与 a r t s arts arts 并不相似。这里将两者放在同一组的依据是,题目规定要确定一个字符串是否是一个组的,只要判断该字符串是否与组中至少有一个字符串相似,这即是是第二个需要注意的点。
这个示例中, t a r s tars tars 与 r a t s rats rats 相似放在同一组中,而 r a t s rats rats 与 a r t s arts arts 相似,那么 a r t s arts arts 也放在当前组。而 s t a r star star 与其他三个字符串均不相似,所以自己一个组。
现在题目要求找出 s t r s strs strs 中有多少个相似的字符串组?
在这里,我们将每个字符串都看成是图的顶点,只要能够确定两个字符串是相似的,就用边将两个顶点连接合并。就是说只要两个字符串相似就会分在同一组,在同个连通分量,那么题目也就转换为求图的顶点合并后最终会有多少个连通分量。
那么我们可以用并查集的方法来解决。具体的思路如下:
- 首先每个字符串都自成一个连通分量;
- 两两比对字符串,判断两个字符串是否相似:
- 如果相似,且还未在同一个组中,那么将两个字符串进行合并,同时更新连通分量数目;
- 如果不相似,不做处理。
- 所有顶点都确认后,返回连通分量的数目。
具体的代码实现如下。
class UnionFind:
def __init__(self, n):
self.parent = [i for i in range(n)]
self.count = n
def find(self, x):
if x != self.parent[x]:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, x, y):
x_root = self.find(x)
y_root = self.find(y)
if x_root != y_root:
self.parent[x_root] = y_root
self.count -= 1
def connected(self, x, y):
return self.find(x) == self.find(y)
def get_count(self):
return self.count
class Solution:
def numSimilarGroups(self, strs: List[str]) -> int:
def is_similar(x, y):
"""查看 x 与 y 是否相似
Args:
x: 其中一个字符串
y: 另外一个字符串
"""
cnt = 0
for a, b in zip(x, y):
if a != b:
cnt += 1
if cnt > 2:
return False
return True
n = len(strs)
uf = UnionFind(n)
for x in range(n):
for y in range(x + 1, n):
# 相似,但还未在同一组时,进行合并
if not uf.connected(x, y) and is_similar(strs[x], strs[y]):
uf.union(x, y)
return uf.get_count()
欢迎关注
公众号 【书所集录】
如有错误,烦请指出,欢迎指点交流。若觉得写得还不错,麻烦点个赞👍,谢谢。