字符串的匹配(KMP和sunday算法详解)

之前一直用的kmp来做字符串的匹配题目,直到今日才知道还有sunday这种高效又简单的算法,虽然不能百分之一万的保证准确性,我也没有看sunday算法的相关证明,不过学习了之后确实觉得巧妙,今天我就好好写写这两种算法。

第一 经典的kmp:

kmp的核心就是求next数组,而求next数组,主要就是以下几步:
每一个next[i]的值都代表着i前面的字符的最大回文长度。因此,我们设next[0]=-1,因为位置0前面没有字符,然后设next[1]=0,因为1前面只有0一个字符·,所以为零。

然后我们将一个计数器记零,这是当前最大kmp匹配长度+1,将要求的next的位置指针指向2,然后一路往下,

匹配的规则就是:看当前位置的字符与计数器所在的字符是否相等,因为之前的是最长字符串,已经匹配完了,都相等,如果这个字符也相等,那么当前位置的next值就是上一个next加一。如果不相等,就要把计数器跳到最长字符串的尾端的位置的next,找到最长字符串里面的最长回文字符串,看看是不是相等,直到相等加一,或者计数器跳至负一,游戏结束,将next置零。

现在看实现:

void getnext(vector<int> &next,string str){
   next[0]=-1;
   next[1]=0;
   int pos=2;
   int kmp=0;
   while(pos<str.size()){
      if(str[pos-1]==str[kmp]){   //如果pos前面的位置的字符与他的最大回文的后面那个位置相等
        next[pos++]=++kmp;}
      else if(kmp>0){
         kmp=next[kmp];}
      else next[pos++]=0;
   }

好了,现在我们有了这个next数组,就可以去推原始字符串了。

int getindexof(string ss,string s){
   int size=ss.size();
   vector<int>next(s.size());
   getnext(next,s);
   int i=0;
   int j=0;
   while(i<size){
     if(ss[i]==s[j]){
       i++;
       j++;
     }
     else if(next[j]==-1){
       i++;
     else j=next[j];
     if(j==s.size())
        return i-j;
   }
return -1;
}

如果主串和匹配串字符相同,将他们一起下滑一个单位,如果不同,将匹配串下滑到自己的next值的单位,如果为零表示没有一个一样的,主串往后面滑一位。

现在我们来看看一个更方便快捷的sunday算法:

sunday算法的基本思路就是:给你一个主串和一个匹配串,先匹配一下他们的头看相等不相等,如果相等,后滑一位,匹配下一位,如果不相等,直接在主串上面后滑匹配串长度的位置,然后滑动匹配串看当前字符在匹配串中有没有出现,如果没出现,直接滑动匹配串长度,如果出现,滑动匹配串至与主串一致,然后重新进行一步骤:

int SundaySearch(string text, string pattern) { 
	int i = 0;
	int j = 0;
	int k;
	int m = pattern.size();
	if (text.size() <= 0 || m <= 0) return -1;
	for (; i <text.size();) {
		if (text[i] != pattern[j]) {
			for (k = pattern.size() - 1; k >= 0; k--)
			{
				if (pattern[k] == text[m])
					break;
			}
			i = m - k;
			j = 0;
			m = i + pattern.size();
		}
		else {
			if (j == pattern.size()-1)
				return i - j;
			i++;
			j++;
		}
	}
	return -1;
}

 

 

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/qq_42058590/article/details/84037107
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞