题目描述
✅ 466. 统计重复个数
思路分析
解法一:循环节检测(推荐)
核心思路:
- 将 s1 重复 n1 次,从中删去 s2 的字符,统计能匹配多少个完整 s2;最终结果为匹配总数除以 n2
- 关键优化:遍历 s1 时记录每轮结束时 s2 的索引位置,若某个索引位置出现重复,则找到了循环节
-
| 找到循环节后,可以直接计算大段重复的贡献,再单独处理首尾不完整的部分,从而避免 O(n1 × |
s1 |
) 的暴力枚举 |
-
| 循环节长度最多为 |
s2 |
,因此只需遍历至多 |
s2 |
+ 1 轮 s1 即可找到循环 |
复杂度分析:
-
|
时间复杂度:O( |
s1 |
× |
s2 |
),其中循环节检测最多执行 |
s2 |
轮,每轮遍历 s1 |
-
|
空间复杂度:O( |
s2 |
),存储每个 s2 索引位置对应的状态 |
class Solution {
public int getMaxRepetitions(String s1, int n1, String s2, int n2) {
int len1 = s1.length();
int len2 = s2.length();
// indexMap[i] 记录:s2 索引为 i 时,完整遍历了几轮 s1 以及匹配了多少个 s2
int[] s1Count = new int[len2 + 1];
int[] s2Count = new int[len2 + 1];
int s2Index = 0;
int s2Total = 0;
for (int i = 0; i < n1; i++) {
for (int j = 0; j < len1; j++) {
if (s1.charAt(j) == s2.charAt(s2Index)) {
s2Index++;
if (s2Index == len2) {
s2Index = 0;
s2Total++;
}
}
}
// 记录第 i 轮结束时的状态
s1Count[i] = i;
s2Count[i] = s2Total;
// 检测循环节:s2Index 已经出现过
for (int k = 0; k < i; k++) {
if (s2Index == k % len2) {
// 找到循环节,计算前缀 + 完整循环 + 后缀
int prefixS2 = s2Count[k];
int cycleS2 = s2Total - prefixS2;
int cycleLen = i - k;
int remainRounds = (n1 - k - 1) % cycleLen;
int totalS2 = prefixS2 + cycleS2 * ((n1 - k - 1) / cycleLen) + (s2Count[k + remainRounds] - prefixS2);
return totalS2 / n2;
}
}
}
return s2Total / n2;
}
}
func getMaxRepetitions(s1 string, n1 int, s2 string, n2 int) int {
len1 := len(s1)
len2 := len(s2)
// 记录每轮 s1 结束时 s2 的匹配总数
s2CountPerRound := make([]int, n1)
s2IndexPerRound := make([]int, n1)
s2Index := 0
s2Total := 0
for i := 0; i < n1; i++ {
for j := 0; j < len1; j++ {
if s1[j] == s2[s2Index] {
s2Index++
if s2Index == len2 {
s2Index = 0
s2Total++
}
}
}
s2CountPerRound[i] = s2Total
s2IndexPerRound[i] = s2Index
// 检测循环节
for k := 0; k < i; k++ {
if s2IndexPerRound[k] == s2Index {
prefixS2 := s2CountPerRound[k]
cycleS2 := s2Total - prefixS2
cycleLen := i - k
remainRounds := (n1 - k - 1) % cycleLen
totalS2 := prefixS2 + cycleS2*((n1-k-1)/cycleLen) + (s2CountPerRound[k+remainRounds] - prefixS2)
return totalS2 / n2
}
}
}
return s2Total / n2
}
相似题目
版权声明:
本博客所有文章除特别声明外,均采用
CC BY-NC-SA 4.0
许可协议,转载请注明出处!