LeetCode 466. Count The Repetitions 循环节

231 篇文章 0 订阅

Define S = [s,n] as the string S which consists of n connected strings s. For example, ["abc", 3] ="abcabcabc".

On the other hand, we define that string s1 can be obtained from string s2 if we can remove some characters from s2 such that it becomes s1. For example, “abc” can be obtained from “abdbec” based on our definition, but it can not be obtained from “acbbe”.

You are given two non-empty strings s1 and s2 (each at most 100 characters long) and two integers 0 ≤ n1 ≤ 106 and 1 ≤ n2 ≤ 106. Now consider the strings S1 and S2, where S1=[s1,n1] and S2=[s2,n2]. Find the maximum integer M such that [S2,M] can be obtained from S1.

Example:

Input:
s1="acb", n1=4
s2="ab", n2=2

Return:
2

---------------------------------------------------------------------------------

这题最开始的想法是把s1*n1和s2*n2全部展开,这样复杂度为O(max(s1*n1,s2*n2))

再进一步简化,数一下s1*n1里面有多少个s2即可,最后除一下n2,复杂度O(max(s1*n1,s2))

后面才意识到这题的考点是怎么简化n1,上面两种方法都会超时。。。

简化的思路是观察下面一段匹配代码,index的变化会出现周期性,当上次(s1pre,s2pre)匹配到s2的index时,下次(s1cnt,s2cnt)一直匹配下去还会匹配到s2的index,此后一直循环,类似于无限循环小数的循环节。。。因此,循环前有零头,循环后也可能有零头,再加上中间循环的,就是结果。

        s1cnt, index, s2cnt = 0, 0, 0
        while True:
            s1cnt += 1
            for ch in s1:
                if ch == s2[index]:
                    index += 1
                    if index == len(s2):
                        s2cnt, index = s2cnt + 1, 0

注意每次s1完整的遍历完一遍,都会有对应的s2cnt和index变化,如果index遍历了len(s2)+1次还没有循环,那是不可能的,因为鸽巢原理(即使s1没法完全覆盖s2,index走不到头,index的值也会很快循环)。最终的代码如下:

class Solution:
    def getMaxRepetitions(self, s1: str, n1: int, s2: str, n2: int) -> int:
        l1,l2,s1cnt,s2cnt,index,dic,res = len(s1),len(s2),0,0,0,{},0
        while (True):
            s1cnt+=1
            for ch in s1:
                if (ch == s2[index]):
                    index += 1
                if (index == l2):
                    index,s2cnt = 0, s2cnt+1
            if (index not in dic):
                dic[index] = (s1cnt,s2cnt)
            else:
                (s1pre,s2pre) = dic[index]
                res = s2cnt+(n1-s1cnt)//(s1cnt-s1pre)*(s2cnt-s2pre) #bug2: res = s2pre+(n1-s1cnt)//(s1cnt-s1pre)*(s2cnt-s2pre)
                print('s1pre={0} s2pre={1} s1cnt={2} s2cnt={3} res={4}'.format(s1pre, s2pre, s1cnt, s2cnt, res))
                break
            if (s1cnt == n1): #bug1: s1cnt == n2+1
                return s2cnt // n2

        for _ in range((n1-s1cnt) % (s1cnt-s1pre)):
            for ch in s1:
                if (ch == s2[index]):
                    index += 1
                if (index == l2):
                    index,res = 0, res+1
        return res//n2

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值