
解法
这个题目首先要转化成S1里总共有多少个s2,然后再整除n2就是M的值。
基于官方解答的思想但是不做法不太一样
中心思想是循环!就跟判断循环小数似的
我们需要找到一个对齐方式,然后判断某个模式是否循环。
比如说,对于官解例子里的s1="abaacdbac"和s2="adcbd"。
官解找的对齐模式是 遍历到s1的第一个字母时,s2的哪个下标之前的字母已经完成,于是我们有:
abaacdbac abaacdbac abaacdbac abaacdbac abaacdbac
a d c b d a d c b d a d
0 3 1 3 1
不难发现这个是重复的
具体请走官解
我这里找的对齐模式是:s2的最后一个字母对应s1的哪个下标,令s1="abab",s2="baab"我们有:
abab abab abab abab abab
ba ab b a ab ba ab b
1 3 1
5 11 17
可以看出肯定是131313……地循环了。
当我们在真实下标i处对齐了s2的最后一位,那么此时的对应下标为i%l1。如果在前面已经出现过这个下标了,跟判断循环小数一样,循环节就前面的i%l1处开始。
假设从前面在发现循环节之前已经对齐了a个s2,分别编号为0,...,a-1,i%l1所处的编号为b,表示循环节从编号b处开始。
编号为i的对齐处的真实下标为idx[i]
那么循环节的真实长度为L=i-idx[b]
令L1=l1*n1,对于剩下的L1-idx[b]个字符,假设L1-idx[b]=xL+y,其中x=(L1-idx[b])//L,y = (L1-idx[b])%L
现在我们来判断S1里有多少个s2,首先,循环节前肯定有b个,然后x个循环节里肯定有a-b个,难点在于剩下的y个字符里有多少个。
不难发现,对于b<=k<a,idx[k]-idx[b]表示这个对齐处到循环节开始处的距离,如果idx[k]-idx[b]<=y,那么剩下的y个字符肯定能至少构成k-b+1个s2,所以我们要找到满足这个不等式的最大的k。
最后s2的数量为:k+1+x*(a-b)
几个需要注意的地方:
- 真实下标
i不能超过S1的长度L1 - 也有可能由于
n1太小所以找不到循环节,甚至有可能s1根本没法组成s2,要注意处理
class Solution(object):
def getMaxRepetitions(self, s1, n1, s2, n2):
"""
:type s1: str
:type n1: int
:type s2: str
:type n2: int
:rtype: int
"""
from bisect import bisect_right
if n1==0:
return 0
l1,l2 = len(s1),len(s2)
idx = {}
f = []
i = j = 0
L1 = l1*n1
while i<L1:
while i<L1 and s1[i%l1]!=s2[j%l2]:
i += 1
if i<L1 and (j+1)%l2==0:
if i%l1 not in idx:
idx[i%l1] = len(f)
f.append(i)
else:
b = idx[i%l1]
a = len(idx)
rest = L1-f[b]
L = i-f[b]
k = bisect_right(f,rest%L+f[b]-1) if rest%L else b
# print a,b,rest,L
# print idx,f
ans = (rest//L)*(a-b)+k
return ans//n2
i += 1
j += 1
return len(f)//n2
本文介绍了一种新颖的方法来解决字符串重复次数的问题,通过寻找循环模式,特别是s2的最后一个字母在s1中对应的下标,从而高效计算s1中s2的重复次数。这种方法类似于判断循环小数,关键在于确定循环节的起始位置。
278

被折叠的 条评论
为什么被折叠?



