LeetCode 466 - 统计重复个数

题目描述

466. 统计重复个数

解法:找循环节(Python)

详细参考 liqing官方解
以 [“abaacdbac”, 100],[“adcbd”, 4] 为栗子,说明一下什么叫循环节
在这里插入图片描述
在这里插入图片描述
通过上面两图可以很清楚地理解到什么是循环节,但问题是在于怎么找到循环节?

下面代码中的 recall 是我们用来找循环节的变量,它是一个哈希映射。我们如何找循环节?

假设我们遍历了 s1cnt 个 s1,此时匹配到了第 s2cnt 个 s2 中的第 index 个字符。如果我们之前遍历了 s1cnt’ 个 s1 时,匹配到的是第 s2cnt’ 个 s2 中同样的第 index 个字符,那么就有循环节了。

我们用 (s1cnt’, s2cnt’, index) 和 (s1cnt, s2cnt, index) 表示两次包含相同 index 的匹配结果,那么哈希映射中的键就是 index,值就是 (s1cnt’, s2cnt’) 这个二元组,循环节就是;

  • 前 s1cnt’ 个 s1 包含了 s2cnt’ 个 s2
  • 以后的每 (s1cnt - s1cnt’) 个 s1 包含了 (s2cnt - s2cnt’) 个 s2

那么最后还会剩下 (n1 - s1cnt’) % (s1cnt - s1cnt’) 个 s1, 我们对这些与 s2 进行暴力匹配,注意 s2 要从第 index 个字符开始匹配。

class Solution:
    def getMaxRepetitions(self, s1: str, n1: int, s2: str, n2: int) -> int:
        if n1 == 0: return 0
        s1cnt, s2cnt, indx = 0, 0, 0
        recall = dict()
        while True:
            # 我们多遍历一个s1,看看能不能找到循环节
            s1cnt += 1
            for ch in s1:
                if ch == s2[indx]:
                    indx += 1
                    if indx == len(s2):
                        s2cnt += 1
                        indx = 0
            # 还没有找到循环节,所有s1就用完了
            if s1cnt == n1:
                return s2cnt // n2 
            # 出现了之前的indx,表示找到了循环节
            if indx in recall:
                s1cnt_pre, s2cnt_pre = recall[indx]
                # 前 s1cnt' 个 s1 包含了 s2cnt' 个 s2
                pre_loop = (s1cnt_pre, s2cnt_pre)
                # 以后的每 (s1cnt - s1cnt')个 s1 包含了s2cnt - s2cnt') 个 s2
                in_loop = (s1cnt - s1cnt_pre, s2cnt - s2cnt_pre)
                break
            else:
                recall[indx] = (s1cnt, s2cnt)
        # ans 存储的是 S1 包含的 s2 的数量, 考虑之前的pre_loop 和 in_loop
        ans = pre_loop[1] + (n1 - pre_loop[0]) // in_loop[0] * in_loop[1]
        # S1 的末尾还剩下一些 s1, 我们暴力进行匹配
        rest = (n1 - pre_loop[0]) % in_loop[0]
        for i in range(rest):
            for ch in s1:
                if ch == s2[indx]:
                    indx += 1
                    if indx == len(s2):
                        ans += 1
                        indx = 0
        # S1 包含 ans 个 s2, 那么就包含 ans / n2 个 s2
        return ans // n2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值