Explicación detallada del algoritmo KMP con preguntas de práctica.

Algoritmo KMP

1. Breve introducción

El algoritmo KMP se usa para la coincidencia de cadenas para devolver la posición inicial de la cadena coincidente con éxito, y la complejidad de tiempo es O (N)

La función indexOf viene con Java, y la función indexOf es una versión optimizada de KMP, que solo optimiza el tiempo constante.

2.siguiente matriz

efecto

  • Puede acelerar el proceso de emparejamiento sin emparejamiento violento.
  • La siguiente matriz guarda la longitud máxima coincidente de la cadena de prefijo y la cadena de sufijo (sin incluir la cadena en sí)

Proceso de implementación

  • next[0]El valor predeterminado es -1, que se especifica artificialmente y se utiliza para juicios posteriores.
  • next[1]=0, i=1cuando [0,i-1]solo hay un carácter en el rango, por lo que la longitud del prefijo y la longitud del sufijo son 0, porque las longitudes del prefijo y el sufijo no se incluyen al calcular
  • Recorriendo la cuerda desde i=2el principio, hay tres situaciones generales:
    • Caso 1: i-1el carácter en la posición es igual a la posición inicial del prefijo que se va a emparejar, next[i]igual a la posición inicial del prefijo más 1, la expresiónnext[i]=++index
    • Caso 2: si el prefijo y el sufijo no coinciden correctamente, nextbusque la posición del prefijo correspondiente en el subíndice de índice de la matriz y la expresiónindex=next[index]
    • Caso 3: el prefijo y el sufijo no coinciden correctamente y la matriz siguiente ya no puede buscar valores.next[i]=0

Proceso de implementación de matriz gráfica siguiente
subcadena de destinoinserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

siguiente código de matriz

   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. Función de comparación de cadena principal y subcadena

proceso

  • Llame a la función getNext para obtener la siguiente matriz de subcadenas
  • Use iy jcomo subíndices para recorrer la cadena principal str1y la subcadena respectivamentestr2
  • Hay tres casos en los que ninguno iyj
  • Caso 1: el carácter en la posición actual de la cadena principal es igual al carácter en la posición actual de la subcadena, iy jambas sumas se incrementan
  • Situación 2: cuando la siguiente matriz de la subcadena es igual a -1, es decir, next[0]el valor especificado artificialmente, o jigual a 0, significa que la coincidencia falló y ise incrementará, jmanteniendo 0 sin cambios
  • Caso 3: El carácter en la posición actual de la cadena principal no es igual al carácter en la posición actual de la subcadena En este momento j>0, encuentre la posición del prefijo anterior en la siguiente matriz
  • El último jvalor a verificar es si es igual a la longitud de la subcadena.Si es igual a la longitud de la subcadena, significa que la coincidencia es exitosa, y luego regresar significa que la coincidencia comienza desde la posición de i-jla i-jprincipal cadena.
  • Devuelve -1 si la coincidencia falla

el código

   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. Código general

#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. Temas relacionados con KMP

Número mínimo de caracteres para agregar

Dada una cadena str, solo puede agregar caracteres después de str para generar una cadena más larga. La cadena más larga debe contener dos strs, y las posiciones iniciales de las dos strs no pueden ser las mismas. Encuentre el número mínimo de caracteres para agregar.

Descripción de entrada:
ingrese una línea que indique la cadena original

Descripción de la salida:
genera un número entero que indica el número mínimo de caracteres necesarios para agregar

Ejemplo 1
entrada
123123
salida
3

Ejemplo 2
entrada
11111
salida
1

tren de pensamiento

  • De acuerdo con el significado de la pregunta, hay tres situaciones
    • Caso 1: un carácter, la respuesta es 1, solo agregue un carácter
    • Situación 2: dos caracteres, juzgue si los dos caracteres son iguales, si son iguales, la respuesta es la longitud de la cadena, porque esta cadena debe agregarse, si son diferentes, la respuesta es 1, solo use el primer caracter solo agrégalo
    • Caso 3: varios caracteres, la siguiente matriz en la última posición de la cadena, porque el significado de la siguiente matriz es la longitud máxima coincidente entre el prefijo y el sufijo. Entonces la respuesta es la longitud de la cadena next[str.length()]menos 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;
}

artículo recomendado

Explicación detallada del algoritmo de Mancher con preguntas de práctica.

Supongo que te gusta

Origin blog.csdn.net/weixin_44839362/article/details/117134881
Recomendado
Clasificación