Algorithme KMP
1. Brève introduction
L'algorithme KMP est utilisé pour la mise en correspondance des chaînes afin de renvoyer la position de départ de la chaîne mise en correspondance avec succès, et la complexité temporelle est O(N)
La fonction indexOf est fournie avec Java et la fonction indexOf est une version optimisée de KMP, qui optimise uniquement le temps constant.
2.tableau suivant
effet
- Il peut accélérer le processus de correspondance sans correspondance violente
- Le tableau suivant enregistre la longueur maximale correspondante de la chaîne de préfixe et de la chaîne de suffixe (sans compter la chaîne elle-même)
Processus de mise en œuvre
next[0]
La valeur par défaut est -1, qui est artificiellement spécifiée et utilisée pour les jugements ultérieursnext[1]=0
,i=1
lorsqu'il[0,i-1]
n'y a qu'un seul caractère dans la plage, la longueur du préfixe et la longueur du suffixe sont donc 0, car les longueurs du préfixe et du suffixe ne s'incluent pas lors du calcul- En parcourant la chaîne depuis
i=2
le début, il existe trois situations générales :- Cas 1 :
i-1
Le caractère à la position est égal à la position de départ du préfixe à rechercher,next[i]
égal à la position de départ du préfixe plus 1, l'expressionnext[i]=++index
- Cas 2 : si le préfixe et le suffixe ne correspondent pas correctement,
next
recherchez la position de préfixe correspondante dans l'indice d'index du tableau et l'expressionindex=next[index]
- Cas 3 : le préfixe et le suffixe ne correspondent pas correctement et le tableau suivant ne peut plus rechercher de valeurs.
next[i]=0
- Cas 1 :
Processus de mise en œuvre graphique de la prochaine baie
code de tableau suivant
vector<int> getNext(string str) {
// 每个位置字符串的前缀与后缀最大匹配长度,不包含整串
vector<int> next(str.size());
next[0] = -1; //人为规定,0号位置的值是-1
next[1] = 0;
int i = 2; // 从2开始遍历str
// index代表当前是哪个位置的字符,在和index+1也就是i位置比较
int index = 0; // index既用来作为下标访问,也作为值
while (i < next.size()) {
// str[i-1]代表后缀开始的位置, str[index]代表前缀开始的位置
// index保存了上一次匹配的最大长度, str[index]代表了当前前缀位置, 可以通过这个来进行加速匹配
if (str[i - 1] == str[index]) {
// 如果str[i-1](后缀待匹配的字符) 等于 str[index](前缀待匹配的字符)
// next数组i位置的值 直接等于上次最大匹配长度+1
next[i++] = ++index;
}
else if (index > 0) {
// 后缀与前缀没有匹配成功, 并且index还可以往前找 next[index]的前缀, 也就是找当前前缀的前缀开始位置
index = next[index];
}
else{
// index=0, 没有前缀了, 长度记为0
next[i++] = 0;
}
}
return next;
}
3. Fonction de comparaison de chaîne principale et de sous-chaîne
processus
- Appelez la fonction getNext pour obtenir le prochain tableau de sous-chaînes
- Utilisez
i
etj
comme indices pour parcourir la chaîne principalestr1
et la sous-chaîne respectivementstr2
- Il y a trois cas où ni
i
etj
- Cas 1 : le caractère à la position actuelle de la chaîne principale est égal au caractère à la position actuelle de la sous-chaîne,
i
etj
les deux sommes sont incrémentées - Situation 2 : lorsque le tableau suivant de la sous-chaîne est égal à -1, c'est-à-dire
next[0]
la valeur spécifiée artificiellement, ouj
égale à 0, cela signifie que la correspondance a échoué eti
qu'elle sera incrémentée,j
en gardant 0 inchangé - Cas 3 : le caractère à la position actuelle de la chaîne principale n'est pas égal au caractère à la position actuelle de la sous-chaîne. À ce stade,
j>0
recherchez la position du préfixe précédent dans le tableau suivant - La dernière
j
valeur à vérifier est si elle est égale à la longueur de la sous-chaîne. Si elle est égale à la longueur de la sous-chaîne, cela signifie que la correspondance est réussie, puis revenir signifie que la correspondance commence à partir de la position de lai-j
chaînei-j
principale chaîne. - Renvoie -1 si la correspondance échoue
le code
int getIndex(string str1, string str2) {
vector<int> next = getNext(str2);
int i = 0;
int j = 0;
while (i < str1.size() && j < str2.size()) {
if (str1[i] == str2[j]) {
i++;
j++;
}else if (next[j] == -1) {
i++;
}else{
j = next[j];
}
}
if (j == str2.size()) {
return i - j;
}
return -1;
}
4. Code global
#include<iostream>
#include<string>
#include<vector>
using namespace std;
vector<int> getNext(string str) {
// 每个位置字符串的前缀与后缀最大匹配长度,不包含整串
vector<int> next(str.size());
next[0] = -1; //人为规定,0号位置的值是-1
next[1] = 0;
int i = 2; // 从2开始遍历str
// index代表当前是哪个位置的字符,在和index+1也就是i位置比较
int index = 0; // index既用来作为下标访问,也作为值
while (i < next.size()) {
// str[i-1]代表后缀开始的位置, str[index]代表前缀开始的位置
// index保存了上一次匹配的最大长度, str[index]代表了当前前缀位置, 可以通过这个来进行加速匹配
if (str[i - 1] == str[index]) {
// 如果str[i-1](后缀待匹配的字符) 等于 str[index](前缀待匹配的字符)
// next数组i位置的值 直接等于上次最大匹配长度+1
next[i++] = ++index;
}
else if (index > 0) {
// 后缀与前缀没有匹配成功, 并且index还可以往前找 next[index]的前缀, 也就是找当前前缀的前缀开始位置
index = next[index];
}
else{
// index=0, 没有前缀了, 长度记为0
next[i++] = 0;
}
}
return next;
}
int getIndex(string str1, string str2) {
vector<int> next = getNext(str2);
int i = 0;
int j = 0;
while (i < str1.size() && j < str2.size()) {
if (str1[i] == str2[j]) {
i++;
j++;
}else if (next[j] == -1) {
i++;
}else{
j = next[j];
}
}
if (j == str2.size()) {
return i - j;
}
return -1;
}
int main() {
// 在str1中查找有没有子串str2
string str1 = "abbcabcccc";
string str2 = "abcabc";
//cin >> str1 >> str2;
int index = getIndex(str1, str2);
cout << index;
return 0;
}
5. Sujets connexes sur KMP
Nombre minimum de caractères à ajouter
Étant donné une chaîne str, vous ne pouvez ajouter des caractères qu'après str pour générer une chaîne plus longue. La chaîne la plus longue doit contenir deux chaînes, et les positions de départ des deux chaînes ne peuvent pas être identiques. Trouvez le nombre minimum de caractères à ajouter.
Description de l'entrée :
entrez une ligne indiquant la chaîne d'origine
Description de la sortie :
génère un entier, indiquant le nombre minimum de caractères à ajouter
Exemple 1
entrée
123123
sortie
3
Exemple 2
entrée
11111
sortie
1
train de pensée
- Selon le sens de la question, il y a trois situations
- Cas 1 : Un caractère, la réponse est 1, ajoutez simplement un caractère
- Situation 2: Deux caractères, jugez si les deux caractères sont identiques, s'ils sont identiques, la réponse est la longueur de la chaîne, car cette chaîne doit être ajoutée, s'ils sont différents, la réponse est 1, utilisez simplement le premier caractère il suffit de l'ajouter
- Cas 3 : plusieurs caractères, le tableau suivant à la dernière position de la chaîne, car la signification du tableau suivant est la longueur de correspondance maximale entre le préfixe et le suffixe. La réponse est donc la longueur de la chaîne
next[str.length()]
moins 1
#include<iostream>
#include<vector>
#include<string>
using namespace std;
int getNext(string str) {
vector<int> next(str.size());
next[0] = -1; //人为规定,0号位置的值是-1
next[1] = 0;
int i = 2; // 从2开始遍历str
int val = 0; // val既用来作为下标访问,也作为值
while (i < next.size()) {
if (str[i - 1] == str[val]) {
next[i++] = ++val;
}
else if (val > 0) {
val = next[val]; // 取出前一个next数组的值
}
else {
next[i++] = 0;
}
}
return next[str.size() - 1];
}
int main() {
string str;
cin >> str;
int ans = 0;
if (str.size() == 0) {
cout << 0;
return 0;
}
else if (str.size() == 1) {
ans = str.size() + str.size();
}
else if (str.size() == 2) {
ans = str[0] == str[1] ? str.size() + 1 : str.size() + str.size();
}
else {
int next = getNext(str);
ans = str.size() + str.size() -1 - next;
}
ans -= str.size();
cout << ans;
return 0;
}
article recommandé
Explication détaillée de l'algorithme de Mancher avec des questions pratiques