试水刷题,先从简单的练起。

题目

466. 统计重复个数

由 n 个连接的字符串 s 组成字符串 S,记作 S = [s,n]。例如,["abc",3]=“abcabcabc”。

如果我们可以从 s2 中删除某些字符使其变为 s1,则称字符串 s1 可以从字符串 s2 获得。例如,根据定义,"abc" 可以从 “abdbec” 获得,但不能从 “acbbe” 获得。

现在给你两个非空字符串 s1 和 s2(每个最多 100 个字符长)和两个整数 0 ≤ n1 ≤ 106 和 1 ≤ n2 ≤ 106。现在考虑字符串 S1 和 S2,其中 S1=[s1,n1] 、S2=[s2,n2] 。

请你找出一个可以满足使[S2,M] 从 S1 获得的最大整数 M 。

示例 1:

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

返回:
2

解题思路

先读懂题目

也不知道是不是出题人故意的,这题还是挺难读懂的,我们不妨换个方式来读

关于字符串 A 从 B 获得

如果我们可以从字符串 B 中删除某些字符使其变为 A,则称字符串 A 可以从字符串 B 获得。
例如,根据定义,"abc" 可以从 “abdbec” 获得,但不能从 “acbbe” 获得。

关于字符串的生成规则(Repeat):

将 n 个字符串 s 连接在一起组成字符串 R,记作R = [s,n]
例如,R ["abc",3]=“abcabcabc”

最后是题目要求:

现在给你两个非空字符串 Sa 和 Sb(每个最多 100 个字符长)和两个整数 0 ≤ Na ≤ 10⁶ 和 1 ≤ Nb ≤ 10⁶。
现在考虑字符串 Ra 和 Rb,其中 Ra=[Sa,Na]Rb=[Sb,Nb]
现在我们希望构造一个字符串 Rc=[Rb, M] ,同时又要保证 Rc 能够从 Ra 获得。
请你找出 M 最大取值是多少 。

以题目样例来说:

Ra = ["acb", 4] ,其实就是 Sa = "acb", Ra = "acbacbacbacb", Na = 4
Rb = ["ab", 2],其实就是 Sb = "ab", Rb = "abab", Nb = 2
Rb 重复 M 次后,仍然能够 从 Ra 中获得,求 M 的最大取值

这样拆分重组之后,应该能比之前容易读懂一点了。

寻找循环段落

这题其实思路也蛮简单的,其实就是尽可能的找出循环来减少遍历的次数。

我们以官方题解的示例数据为例:

Ra = ["abaacdbac", 100]
Rb = ["adcbd", 4]

先画简单的图来示意一下,能够注意到的是,似乎在开头这部分,并没有出现循环。

那么我们再多来几段试试看:

从图中可以看到,随着 Rb 的不断重复,首字母 a 的位置变的稳定了起来,看起来也比较有规律了,但是好像和 Rb 对的不是很齐的样子,不太好算啊。

这时我们可以换另一个思路来『上色』,按下面这种黄绿的方式来分组。

先抛开前面的 adc 三个字母不管,我们以两个 Sa 为一组来看,循环的部分就规整了很多。

如上图所示,前面有前导的 abc 三个字母占了点位置,末尾有我也不知道是什么样子的结尾部分;

但是可以肯定的是,中间的部分肯定是 bdadc 的不断循环,同时每个循环占用了 2 个 Sa 的长度。

接下来的工作,就是把这些循环的部分优化掉了。

其实根据上图我们可以看到,当我们遍历到第一次出现循环的时候,计算出有多少个循环,直接跳到 End 的位置做收尾工作就好了。

解答

基本上按照上面的思路按部就班的写代码就好了,计算的时候稍微留意一下 Rb 的下标还在自增。

func getMaxRepetitions(s1 string, n1 int, s2 string, n2 int) int {
    len1, len2 := len(s1), len(s2)
    index1, index2 := 0, 0 // 注意此处直接使用 Ra Rb 的下标,不取模

    if len1 == 0 || len2 == 0 || len1*n1 < len2*n2 {
        return 0
    }

    map1, map2 := make(map[int]int), make(map[int]int)
    ans := 0 // 注意,此处存储的是 Ra 中 Sb 的个数,而非 Ra 中 Rb 的个数

    for index1/len1 < n1 { // 遍历整个 Ra
        if index1%len1 == len1-1 { //在 Sa 末尾
            if val, ok := map1[index2%len2]; ok { // 出现了循环,进行快进
                cycleLen := index1/len1 - val/len1                 // 每个循环占多少个 Sa
                cycleNum := (n1 - 1 - index1/len1) / cycleLen      // 还有多少个循环
                cycleS2Num := index2/len2 - map2[index2%len2]/len2 // 每个循环含有多少个 Sb

                index1 += cycleNum * cycleLen * len1 // 将 Ra 快进到相应的位置
                ans += cycleNum * cycleS2Num         // 把快进部分的答案数量加上
            } else { // 第一次,注意存储的是未取模的
                map1[index2%len2] = index1
                map2[index2%len2] = index2
            }

        }

        if s1[index1%len1] == s2[index2%len2] {
            if index2%len2 == len2-1 {
                ans += 1
            }
            index2 += 1
        }
        index1 += 1
    }
    return ans / n2
}

0ms 2MB ,性能还是蛮不错的。

文章目录