【并查集】LeetCode 839. 相似字符串组

839. 相似字符串组


题目来源:力扣(LeetCode)https://leetcode-cn.com/problems/similar-string-groups/

题目


如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等,那么称 XY 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。

例如,"tars""rats" 是相似的 (交换 02 的位置); "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 tarsratsarts 均不相似,因为 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()

欢迎关注


公众号 【书所集录


如有错误,烦请指出,欢迎指点交流。若觉得写得还不错,麻烦点个赞👍,谢谢。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值