模板系列 - 字符串处理 -KMP算法

KMP算法解决基础的问题:给两个串,问第二个串是不是第一个串的子串。
KMP算法原理:对于字符串的匹配来说,当前方出现一个不匹配时,传统的方法是向前挪一个重新进行匹配。例如abcxabcxabcdabcdd
abcxabcdabcd当你匹配到第二个x时你会不匹配但是第二个x前面的abc是匹配的,当然如果遇到一个不匹配的就把前面的都舍去重开是更加不现实的因为不能舍。
所以应该从第一个的abc后面的x开始匹配,所以匹配完成。
两个重复及以上就返回就近的匹配到的,既然你的算法都那么设计了,前几个一定都一样数组里面的数据才会增加的。
KMP算法实现:(首先是预处理)对子串处理
void preKMP()
{
    int i =0; int j = -1;
     nextarr[0] = -1;
    while(i < n)
    {
       if(j != -1 && s[i] !=s[j])j =nextarr[j];
       nextarr[++i] = ++j;  }}


判断大串中有没有小串
bool KMP()
{
    int i = 0;int j =-1;
    while(i < b.size())
    {
        if(j!=-1 && b[i] != s[j]) j = nextarr[j];
        i++;j++;
        if(j>=n)
        {
            return true;  }
    }
    return false;
}


判断有多少小串的方法:(KMP变形)
int KMP()
{
    int i = 0;int j =-1;
    int ans = 0;
    while(i < b.size())
    {
        if(j!=-1 && b[i] != s[j]) j = nextarr[j];
        i++;j++;
        if(j>=n)
        {
            ans++;
            j = nextarr[j];
        }
    }
  return ans;
}


这样的话一般的题目不会坑人,但是我要举一个坑人的例子
UVA 1328 Period
题目大意:问一个字符串的子串是不是一个重复字符串
比如aabaabaabaab
前两个的时候是可行的两个a所以是2 2
aabaab是可行的拆成两个字符串aab所以是6 2(前边的数代表子串长度)
同理aabaabaab结果是9 3
aabaabaabaab结果为12 4
看到题目我觉得不是KMP因为不像啊!但是KMP预处理的原理就是找到前面一个一样的的位置比如abcdabcdabcd第二个a里面的值为1意思是他前面一个能匹配的串但是这和这个题有什么关系呢?我其实也想不通一开始,后来一想,如果他里面的匹配(这个是尽量近的所以要用位数减掉数组里面的东西)是他的位数的取余为0的那不就行了!!!
于是预处理完,
加一条语句
 
if(i % (i - nextarr[i]) == 0 && i / (i - nextarr[i]) > 1) 

 
后边那个是控制他不是第一个的,要不前边一堆0都算了
以上





猜你喜欢

转载自blog.csdn.net/h201601060805/article/details/77972169