繁体   English   中英

使用 Knuth Morris 计算每个前缀的出现次数

[英]Counting the number of occurrences of each prefix using Knuth Morris

我正在研究我的竞争性编码技能,我遇到了一篇文章,用于计算字符串中每个前缀的出现次数。 这是问题陈述给定一个长度为 n 的字符串 s。 在问题的第一个变体中,我们要计算每个前缀 s[0…i] 在同一字符串中出现的次数。 在问题的第二个变体中,给出了另一个字符串 t,我们想要计算每个前缀 s[0…i] 在 t 中出现的次数。 我找到了解决办法。

代码:

for (int i = 0; i < n; i++)
    ans[pi[i]]++;
for (int i = n-1; i > 0; i--)
    ans[pi[i-1]] += ans[i];
for (int i = 0; i <= n; i++)
    ans[i]++;

据我所知,前缀是什么,我无法完全理解问题陈述:

例如:字符串:geekforgeek 有前缀 as:{g,ge,gee,geek,geekf,geekfo,geekfor,geekforg,geekforge,geekforgee} 作为正确的前缀。 有人可以帮我这个问题试图计算什么,因为只有这些是出现一次的可用前缀。 提前致谢。

如果你到目前为止我假设你知道prefix_function。 所以我们考虑 string str = "ABACABA" 我们得到它的前缀数组 say pi as = {0, 0, 1, 0, 1, 2, 3} 来存储所有正确前缀的出现(即我们不包括字符串本身) 我们创建一个长度为 str.length()+1 的新数组或向量(根据您的需要)'occ',其中 occ[i] 表示前缀 str[0:i] 的出现次数。

所以当你引用上面的代码时,有三个循环。 首先,我必须解释这些循环实际上在计算什么。 第一个循环很简单,它只计算最长前缀的编号,它也是长度为 i 的字符串中的后缀。 对于前缀“A”,我们与 str[0:3] 和 str[0:5] 的前缀具有相同的后缀,如果仔细观察,可以说“A”是最长的前缀,也是这两个字符串的后缀,因此,我们从上面计算的数组 pi 中得到这个,因为它存储了最长前缀的长度,它也是一个后缀。 同样,对于前缀“AB”,我们将其作为最长的前缀和后缀在 str[1:6] 中,依此类推。 我们得到 occ = {3, 2, 1, 1, 0, 0, 0, 0}。 我希望第一个循环的想法很清楚。

现在,当我们考虑上面前缀“A”的示例时,如果我们观察“ABACABA”,我们会看到在字符串 str[0:7] 中我们也有“A”作为后缀,但不是最长的前缀最长的地方== 后缀是“ABA”,所以在我们的第一个循环中,我们错过了前缀的出现。 还假设如果我们有长度为 l 的前缀,它也是一个后缀并以索引 i 结束,并且为了得到一些长度为 l' < l 我们 go 为 pi[pi[i]-1] 或说 pi[l-1 ] 从前缀 function 可以清楚地看出。 因此,使用数组 pi 的这种方式,我们跟踪在第一个循环中计算的长度小于的前缀。 如果我们知道长度前缀 i 恰好出现 occ[i] 次,那么这个数字必须添加到它的最长后缀(也是前缀)的出现次数上。

第三个循环是我们添加每个前缀的出现。 而在其他两个中,我们只考虑后缀。

代码应该是

 {  for (int i = 0; i < n; i++)
    ans[pi[i]]++;
for (int i = n-1; i > 0; i--)
    ans[pi[i]-1] += ans[i];     ///note the index
for (int i = 0; i <= n; i++)
    ans[i]++;
}

文章是https://cp-algorithms.web.app/string/prefix-function.html#counting-the-number-of-occurrences-of-each-prefix其中错误地提到了该索引。 如果我错了,请纠正我。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM