#include<bits/stdc++.h>
using namespace std;
const int N = 50;
int nex[N];
int main()
{
string s, p;
s = "AABAABBABAAA";
p = "AB";
nex[0] = 0;
int i = 0, j = 1;
while(j < p.length()) //遍历p
{
if(p[i] == p[j]) nex[j++] = ++i; //成功
else
{
if(i > 0) i = nex[i-1]; //普通失败,尝试调整i
else nex[j++] = 0; //彻底失败,为0
}
}
//for(int i = 0; i < p.size(); i++) cout << nex[i] << " ";
i = 0, j = 0;
while(j < s.length()) //遍历s
{
if(p[i] == s[j]) i++, j++; //成功
else
{
if(i > 0) i = nex[i-1]; //普通失败,尝试调整i
else j++; //彻底失败,j增加
}
if(i >= p.length()) //一次匹配结束
{
//cout << j - p.length();
//break; //结束匹配
cout << j - p.length() << " "; //打印起点
i = nex[i-1]; //继续匹配
}
}
注意
i为使用nex数组的p串指针。j在计算nex数组中,为辅助p串指针;在匹配中,为s串指针。
i,j所处的位置为即将进行字符匹配的位置。
i可以表示已经匹配的数目,这决定了为什么字符匹配成功后要++i而不是i++。
而nex的使用要给出失配的前一个索引,即已配对的序列的最右索引。
序号起始为0。因此匹配成功 i = p.length()。
继续匹配为什么要用nex[i-1],是为了找长得和尾巴一样且最长的头,因为有可能前面匹配掉的有一部分是下一次匹配的开头部分。如下图所示。
思路
计算nex —— 匹配
异:遍历p —— 遍历s
同:字符匹配成功(i,j,nex的变化 —— i,j变化 )
同:普通失败,尝试调整
同:完全失败(nex,j变化(nex初值为0的话,等同于j变化) —— j变化)
异:无 匹配成功的后序处理