《算法笔记》编程笔记——第十二章 字符串专题
-
KMP算法
-
给出两个字符串,判断其中一个字符串是否是另一个字符串的子串。如果用暴力求解,时间复杂度将达到O(n*m),如果用KMP算法,时间复杂度仅为O(n + m)。
-
next数组
-
int型数组,其中next[i]表示使子串s[0……i]的前缀s[0……k]等于后缀s[i-k……i]的最大的k。(注意前缀跟后缀可以有部分重叠,但是不能是s[0……i]本身);如果找不到相等的前后缀,就令next[i] = -1. 显然,next[i]就是所求最长相等前后缀中前缀的最后一位的下标
-
next数组求解如下图所示,上框为一种方法,下框为另一种方法
-
求解思路:
①初始化next数组,令j = next[0] = -1.
②让i在1~len-1(len为字符串s长度)范围内遍历,对每个i,执行③④,以求解next[i]。
③不断令j = next[j],直到j回退为-1,或是s[i] == s[j+1]成立。
④如果s[i] == s[j+1],则next[i] = j+ 1,否则next[i] = j。
-
代码如下
//getNext求解长度为len的字符串s的next数组 void getNext(char s[], int len){ int j = -1; next[0] = -1; //第一步初始化j与next数组 //第二步,循环 for(int i = 1; i <= len -1; i++){ //第三步,j更新 while(j != -1 && s[i] != s[j+1]){ j = next[j]; } //第四步,更新next数组 if(s[i] == s[j+1]){ j++; } next[i] = j; } }
-
-
KMP算法
-
总体思路:当字符串不匹配时,不是让j退回到-1,而是退回到最近的j’,使得text[i] == pattern[j’ + 1]成立并且pattern[0……j’]仍然与text的相应位置处于匹配状态,也就是pattern[0……j’]是pattern[0……j]的最长相等前后缀。从这个角度来说,next数组的含义就是当j+1匹配失败时,j应该回退到的位置。
-
求解具体思路:
①初始化j = -1,表示pattern当前已被匹配的最后位。
②让i遍历字符串text,对每个i,执行③④来试图匹配text[i]和pattern[j+1]。
③不断令j = next[j],直到j回退到-1或者text[i] == pattern[j+1]成立 。
④如果text[i] == pattern[j+1],则令j++;如果j达到m-1(m为pattern字字符串的长度),说明pattern是text的子串,返回true。
-
代码实现
//KMP算法,判断pattern是否是text的子//KMP算法,判断pattern是否是text的子串 bool KMP(char text[], char pattern[]){ int n = strlen(text), m = strlen(pattern); getNext(pattern, m);//计算pattern的next数组 int j = -1;//第一步,初始化 //第二步,遍历循环 for(int i = 0; i < n; i++){ //第三步,j更新 while(j != -1 && text[i] != pattern[j+1]){ j = next[j];//不断回退 } if(text[i] == pattern[j+1])j++; //第四步,判断是否完全匹配 if(j == m-1)return true; } return false; }
-
求解pattern在text中出现的次数。
-
思路:
①当j = m-1时表示pattern的第一次成功完全匹配,此时让记录成功匹配次数的变量加1,然后考虑让j回退到next[j]的位置,继续进行下一次的匹配。
-
代码实现
//KMP算法,统计pattern在text中出现的次数 int KMP(char text[], char pattern[]){ int n = strlen(text), m = strlen(pattern); getNext(pattern); int ans = 0, j = -1;//j初始化,ans记录成功匹配次数 for(int i = 0; i < n; i++){ while(j != -1 && text[i] != pattern[j+1]){ j = next[j];//更新j } if(text[i] == pattern[j+1])j++; //这里是与不统计pattern匹配次数的KMP算法不同的地方。 if(j == m-1){ ans++; j = next[j]; } } return ans; }
-
-