Count the string(KMP)

本文介绍了一个字符串匹配问题:计算一个字符串的所有非空前缀在该字符串中出现的次数总和,并提供了一个使用C++实现的解决方案,通过计算next数组来高效解决此问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Count the string

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 12784 Accepted Submission(s): 5899

Problem Description
It is well known that AekdyCoin is good at string problems as well as number theory problems. When given a string s, we can write down all the non-empty prefixes of this string. For example:
s: “abab”
The prefixes are: “a”, “ab”, “aba”, “abab”
For each prefix, we can count the times it matches in s. So we can see that prefix “a” matches twice, “ab” matches twice too, “aba” matches once, and “abab” matches once. Now you are asked to calculate the sum of the match times for all the prefixes. For “abab”, it is 2 + 2 + 1 + 1 = 6.
The answer may be very large, so output the answer mod 10007.

Input
The first line is a single integer T, indicating the number of test cases.
For each case, the first line is an integer n (1 <= n <= 200000), which is the length of string s. A line follows giving the string s. The characters in the strings are all lower-case letters.

Output
For each case, output only one number: the sum of the match times for all the prefixes of s mod 10007.

Sample Input
1
4
abab

Sample Output
6
next 数组 存放的是 [1 ,i-1] 上最大前后缀相等的长度
如果不为0 呢吗 这个字传一定是出现了两次
如果为0 在 1~i-1 只出现了 一次

#include<iostream>
#include<stdio.h>
#include<string>
#include<stdlib.h>
#include<string.h>

using namespace std;
int nxt[200007];//存放最长前后缀公共的长度
string p,str;//模式串 主串
char ch[200007];
void GetNxt(int len)
{
   nxt[0] = nxt[1] = 0;
    for(int i = 1;i<len;i++)
    {
        int j = nxt[i];//nxt[i] 代表当前1~i的子串中 最大前后缀的长度为 nxt[i]
        while(j && ch[i] != ch[j]) j = nxt[j];//没有匹配成功 呢么就一直往前找
        if(ch[i] == ch[j])
            nxt[i+1] = j+1;
        else
            nxt[i+1] = 0;
    }
}
int main()
{
    ios::sync_with_stdio(false);
    int ncase;
    scanf("%d",&ncase);
    while(ncase--)
    {
        int len;
        scanf("%d %s",&len,ch);
        GetNxt(len);
        int num =0;
        /*
        nxt[0] = 0; 代表 abab 的次数
        nxt[1] = 0; 代表 a
        nxt[2] = 0; 代表 ab 次数 :
        nxt[3] = 1; 代表 a的出现的 次数 : 2
        nxt[4] = 2; 代表ab 出现的次数 1
        */
        for(int i = 0;i<len;i++)
        {
            if(nxt[i]) num = (num + 2) %10007;//这里是由于 nxt 数组的特性所决定的 只要 nxt[i] 不为0 呢吗 在 前 1 ~i-1 中 就一定出现了两次
            else
                num = (num + 1 )%10007;//最长前后缀的长度 为0 呢吗 这个子串在 前 1~ i-1 出现了 一次
        }
        if(nxt[len]) num = (num + 1) %10007;//如果最后一个nxt值不为0 那么说明 在前 n 个元素 的最
        printf("%d\n",num %10007 );
    }
    return 0;
}
内容概要:本文档详细介绍了一个基于MATLAB实现的跨尺度注意力机制(CSA)结合Transformer编码器的多变量时间序列预测项目。项目旨在精准捕捉多尺度时间序列特征,提升多变量时间序列的预测性能,降低模型计算复杂度与训练时间,增强模型的解释性和可视化能力。通过跨尺度注意力机制,模型可以同时捕获局部细节和全局趋势,显著提升预测精度和泛化能力。文档还探讨了项目面临的挑战,如多尺度特征融合、多变量复杂依赖关系、计算资源瓶颈等问题,并提出了相应的解决方案。此外,项目模型架构包括跨尺度注意力机制模块、Transformer编码器层和输出预测层,文档最后提供了部分MATLAB代码示例。 适合人群:具备一定编程基础,尤其是熟悉MATLAB和深度学习的科研人员、工程师和研究生。 使用场景及目标:①需要处理多变量、多尺度时间序列数据的研究和应用场景,如金融市场分析、气象预测、工业设备监控、交通流量预测等;②希望深入了解跨尺度注意力机制和Transformer编码器在时间序列预测中的应用;③希望通过MATLAB实现高效的多变量时间序列预测模型,提升预测精度和模型解释性。 其他说明:此项目不仅提供了一种新的技术路径来处理复杂的时间序列数据,还推动了多领域多变量时间序列应用的创新。文档中的代码示例和详细的模型描述有助于读者快速理解和复现该项目,促进学术和技术交流。建议读者在实践中结合自己的数据集进行调试和优化,以达到最佳的预测效果。
### C++ 实现 BF 和 KMP 算法 以下是基于 C++ 的实现代码,用于完成主串 `"ssssssssussu"` 和模式串 `"ussu"` 的匹配操作,并统计比较次数。 #### 1. **BF 方法** BF 方法通过逐一比较主串和模式串中的字符来寻找匹配位置。如果发生失配,则主串指针向前移动一位继续尝试匹配[^2]。 ```cpp #include <iostream> #include <string> using namespace std; // BF算法函数 int bfSearch(const string& S, const string& T, int pos = 0) { int i = pos; // 主串索引 int j = 0; // 模式串索引 int compareCount = 0; // 统计比较次数 while (i < S.length() && j < T.length()) { if (S[i] == T[j]) { // 字符相等则前进 ++compareCount; ++i; ++j; } else { // 失配时重置 ++compareCount; i = i - j + 1; j = 0; } } if (j == T.length()) { // 成功找到匹配 cout << "BF Method Compare Count: " << compareCount << endl; return i - T.length(); } else { // 匹配失败返回-1 return -1; } } int main() { string S = "ssssssssussu"; string T = "ussu"; int result = bfSearch(S, T); if (result != -1) { cout << "Match Position by BF: " << result << endl; } else { cout << "No Match Found by BF." << endl; } return 0; } ``` --- #### 2. **KMP 方法** KMP 方法的核心在于利用部分匹配表(Partial Match Table),从而避免主串指针的回溯。当发生失配时,仅调整模式串的位置以减少不必要的重复比较[^1]。 ```cpp #include <iostream> #include <vector> #include <string> using namespace std; // 构建部分匹配表next数组 vector<int> buildNextArray(const string& pattern) { vector<int> next(pattern.size(), 0); // 初始化为全零 int j = 0; // 前缀长度初始化为0 for (int i = 1; i < pattern.size(); ++i) { while (j > 0 && pattern[i] != pattern[j]) { j = next[j - 1]; // 回退到更短的部分匹配状态 } if (pattern[i] == pattern[j]) { ++j; // 部分匹配长度增加 } next[i] = j; // 记录当前最大公共前后缀长度 } return next; } // KMP算法函数 int kmpSearch(const string& text, const string& pattern) { vector<int> next = buildNextArray(pattern); int i = 0, j = 0; // i为主串索引,j为模式串索引 int compareCount = 0; // 统计比较次数 while (i < text.size() && j < pattern.size()) { if (text[i] == pattern[j]) { // 如果匹配成功 ++compareCount; ++i; ++j; } else if (j > 0) { // 发生失配且j大于0 ++compareCount; j = next[j - 1]; } else { // 发生失配且j等于0 ++compareCount; ++i; } } if (j == pattern.size()) { // 完成匹配 cout << "KMP Method Compare Count: " << compareCount << endl; return i - j; } else { // 未找到匹配 return -1; } } int main() { string S = "ssssssssussu"; string T = "ussu"; int result = kmpSearch(S, T); if (result != -1) { cout << "Match Position by KMP: " << result << endl; } else { cout << "No Match Found by KMP." << endl; } return 0; } ``` --- ### 输出结果对比 运行以上两段程序可以得到如下输出: 对于主串 `ssssssssussu` 和模式串 `ussu`, - 使用 BF 方法:匹配位置为8,比较次数可能较高。 - 使用 KMP 方法:同样匹配位置为8,但由于减少了无意义的比较,其总比较次数显著降低。 具体数值取决于输入数据结构以及实现细节[^3]。 --- ### 性能分析 从理论上讲,在最坏情况下: - BF 算法的时间复杂度为 O(m * n),其中 m 是主串长度,n 是模式串长度。 - KMP 算法的时间复杂度为 O(m + n)[^1]。 因此,针对较长字符串或频繁查询场景下,推荐优先采用 KMP 算法。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值