466 统计重复个数(循环节)

1. 问题描述:

定义 str = [s, n] 表示 str 由 n 个字符串 s 连接构成。
例如,str == ["abc", 3] =="abcabcabc" 。
如果可以从 s2 中删除某些字符使其变为 s1,则称字符串 s1 可以从字符串 s2 获得。
例如,根据定义,s1 = "abc" 可以从 s2 = "abdbec" 获得,仅需要删除加粗且用斜体标识的字符。
现在给你两个字符串 s1 和 s2 和两个整数 n1 和 n2 。由此构造得到两个字符串,其中 str1 = [s1, n1]、str2 = [s2, n2] 。
请你找出一个最大整数 m ,以满足 str = [str2, m] 可以从 str1 获得。

示例 1:
输入:s1 = "acb", n1 = 4, s2 = "ab", n2 = 2
输出:2

示例 2:
输入:s1 = "acb", n1 = 1, s2 = "acb", n2 = 1
输出:1
提示:
1 <= s1.length, s2.length <= 100
s1 和 s2 由小写英文字母组成
1 <= n1, n2 <= 10 ^ 6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-the-repetitions

2. 思路分析:

首先需要理解题目的意思,题目的主要意思是在S1中按顺序找出最多能有多个S2,本质上是在S1中找子序列的个数,其中S1为n1个s1构成的字符串,S2为n2个s2构成的字符串。最简单的方法是暴力枚举,从前往后扫描S1,在扫描的过程中看能够匹配多少个s2,最后除以n2就是答案,由题目可以知道时间复杂度为10 ^ 8所以可能会超时,我们需要优化一下暴力枚举的,降低一下时间复杂度。对于这种字符串重复的问题我们可以考虑一下循环节。因为字符串是重复的所以我们在S1中匹配s2的时候如果能够判断出当前匹配的位置之前已经匹配过说明存在了重复那么后面字符串的匹配过程是一样的,那么直接计算即可。基于这个想法我们可以在每一段s1中匹配s2,使用k来记录当前匹配s2的个数,当匹配到s2的末尾的时候那么从s2下标从0开始匹配(循环匹配s2),为了能够判断出匹配当前第i段的时候出现了循环节,我们可以使用一个哈希表来记录下每一段s1中匹配s2的位置,也即记录下k % len(s2),如果发现当前的k % len(s2)在哈希表中存在说明出现了循环节,前面的一段0~i-1就是循环节,我们可以直接计算剩下的第i + 1~ n1段能够构成多少个循环节,每个循环节匹配了s2的多少个字符,相乘就是剩余的这么多段s1能够匹配s2的字符数目,计算一开始的第一个循环节与剩余不满足一个循环节匹配的s2的字符个数,将这些结果累加起来就是在n1个s1中匹配s2的字符个数,最后除以(len(s2) * n2) 那么就是最终的答案。

3. 代码如下:

class Solution:
    def getMaxRepetitions(self, s1: str, n1: int, s2: str, n2: int) -> int:
        dic = dict()
        # k表示到目前为止匹配了多少个s2中的字符
        k = 0
        res = 0
        # count记录到当前的第i段匹配的s2的字符个数
        count = list()
        t = 0
        # 第一层循环表示是第i段的s1
        for i in range(n1):
            for j in range(len(s1)):
                if s1[j] == s2[k % len(s2)]:
                    k += 1
            count.append(k)
            # 说明出现了循环节, 也即完全匹配了s2, 可能包含多个s2
            if k % len(s2) in dic:
                # 当前循环节有i段s1
                a = i
                # b为循环节匹配的s2的字符个数
                b = k - count[0]
                # 计算剩余的这么多段能够匹配的s2的字符个数
                res += (n1 - i - 1) // a * b
                # 计算剩余的不满足循环节的匹配的s2的字符个数
                for u in range((n1 - i - 1) % i):
                    for j in range(len(s1)):
                        if s1[j] == s2[k % len(s2)]: k += 1
                # res当前记录的是匹配了多少了s2的字符
                res += k
                return res // len(s2) // n2
            # 标记每一段匹配s2的位置
            dic[k % len(s2)] = i
        if not count: return 0
        return count[-1] // len(s2) // n2

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值