get_lps和get_next这两个主要在代码中的区别是什么?
在代码的实现中为何改变了是否为重复与不重复?
两个代码的实现过程是怎么样的?
const int N = 1e6 + 1;
int lps[N];
int nextarray[N];
void get_lps(string pat, int * lps) {
int m = pat.length();
int j = 0, i = 1;
lps[0] = 0;
while (i < m) {
if (pat[j] == pat[i]) {
j++;
lps[i] = j;
i++;
} else if (j != 0) {
j = lps[j - 1];
} else {
lps[i] = 0;
i++;
}
}
}
void get_next(string pat,int* lps)
{
int m = pat.length();
get_lps(pat,lps);
int i;
nextarray[0] = -1;
for(i = m - 2; i >= 0 ; i--){
lps[i+1] = lps[i];}
lps[0]= -1;
for(i=0;i<m;i++)
{
printf("%d",lps[i]);
if(i<m-1)
printf(" ");
}
}
不重复的代码
void KMP(string txt, string pat)
{
//请在下面编写代码
/****Begin/
int n = txt.length();
int m = pat.length();
int i = 0;
int j = 0;
get_lps(pat, lps);
while (i < n && j < m) {
if (txt[i] == pat[j]) {
i++; j++;
} else if (j != 0) {
j = lps[j - 1];
} else {
i++;
}
if (j == m) {
cout << i - j + 1 << endl;
j = lps[j - 1];
}
}
get_next(pat,lps);
}
重复的代码
int Count(string s,string t)
{
int n=s.length();
int m=t.length();
int i=0;
int j=0;
int tot=0;
get_next(t,nt);
while(i<n&&j<m)
{
if(jm-1&&s[i]t[j])
{
tot++;
j=nt[j];
}
if(j-1||s[i]t[j])
{
i++;
j++;
}
else j=nt[j];
}
return tot;
}
int main(int argc, char const *argv[])
{
string txt, pat;
cin >> txt >> pat; //输入文本串和模式串
KMP(txt, pat); //调用kmp算法输出模式串在文本串中的位置以及next[]数组的值
return 0;
}
KMP算法(Knut-Morris-Pratt算法)是用于字符串匹配的一种高效算法,旨在减少搜索过程中的不必要比较。您提到的重复子串个数和不重复子串个数的计算逻辑,虽然基于KMP算法的核心思想,但具体实现上有所不同。接下来,我将逐步分析这两个代码的过程及其不同之处,并重点阐述 get_lps
和 get_next
函数的实现。
在KMP算法中,“最长前缀数组”(LPS, Longest Prefix that is also Suffix)用于减少字符比较的次数。当模式串与文本串匹配失败时,可以利用LPS数组快速跳过一些已知的匹配数据。
get_lps
和get_next
的主要区别get_lps
函数:
pat
的LPS数组。get_next
函数:
next
数组通常将最后一个元素设为-1(表示没有相应的前缀),并且对LPS数组进行了偏移,使得其结构有所不同。void KMP(string txt, string pat) {
int n = txt.length();
int m = pat.length();
int i = 0, j = 0;
get_lps(pat, lps); // 获取LPS数组
while (i < n && j < m) {
if (txt[i] == pat[j]) {
i++;
j++;
} else if (j != 0) {
j = lps[j - 1];
} else {
i++;
}
if (j == m) { // 找到匹配
cout << i - j + 1 << endl; // 输出匹配位置
j = lps[j - 1]; // 继续查找下一个匹配
}
}
}
过程解析:
txt
和模式串 pat
。int Count(string s, string t) {
int n = s.length();
int m = t.length();
int i = 0, j = 0;
int tot = 0;
get_next(t, nt); // 先计算next数组并返回
while (i < n && j < m) {
if (j == m - 1 && s[i] == t[j]) { // 完全匹配
tot++; // 计数这个匹配
j = nt[j]; // 使用next数组跳过某些匹配
}
if (j == m - 1 || s[i] == t[j]) {
i++;
j++;
} else {
j = nt[j]; // 使用next数组回退
}
}
return tot; // 返回成功匹配的总数
}
过程解析:
tot
。next
数组的跳转逻辑更改匹配的处理,确保遍历所有可能的重复匹配,不限制于首次匹配后的行为。总体上,这两者的不同在于处理成功匹配的逻辑以及跳转的方式,以适应不同的数据计数需求。在具体实现过程中,LPS和next数组的计算、利用方式的不同直接影响到算法的执行效果和功能目的。