Algoritmo KMP ------ problema de coincidencia de cadenas

Algoritmo KMP

Problema de coincidencia de cadena de escenario de aplicación

Hay una cadena str1 = "Universidad de Software de Henan Henan, Universidad de Ciencia y Tecnología de Henan, Universidad de Ciencia y Tecnología de Henan" y str2 = "Universidad de Ciencia y Tecnología de Henan"

Ahora tenemos que juzgar si str1 contiene str2, si existe, devuelve la posición de la primera aparición, si no, devuelve -1

Estos son muchos ejemplos de problemas de coincidencia de cadenas

Lo primero que pensamos es el emparejamiento violento.

Si usamos la idea de emparejamiento violento y asumimos que str1 ahora coincide con la posición i y la subcadena str2 coincide con la posición j, entonces:

1. Si el carácter actual coincide correctamente (es decir, str1 [i] == str2 [j] ), entonces i ++, j ++, continúe haciendo coincidir el siguiente carácter

2. Si hay una discrepancia ( es decir, str1 [i]! = Str2 [j] ), establezca i = i- (j-1) y j = 0. Equivalente a cada vez que falla una coincidencia, i retrocede y j se establece en 0 .

3. Si usa métodos violentos para resolverlo, habrá mucho retroceso y solo se moverá un poco a la vez. Si no coincide, pase al siguiente y luego juzgue, perdiendo mucho tiempo. (¡No factible!)

package 字符串匹配问题;
public class ViolenceMatch {
    
    
	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		String str1 = "河南河南软件河南大学河南科技大学软件学院";
		String str2 = "河南科技大学";
		int index = violenceMatch(str1, str2);
		System.out.println(index);
	}
	//暴力匹配算法
	public static int violenceMatch(String str1,String str2){
    
    
		char[] s1 = str1.toCharArray();
		char[] s2 = str2.toCharArray();
		
		int s1Len = s1.length;
		int s2Len = s2.length;
		
		int i = 0;//指向s1
		int j = 0;//指向s2
		while(i<s1Len && j<s2Len){
    
    //保证匹配不越界
			if(s1[i] == s2[j]){
    
    
				//匹配成功
				i++;
				j++;
			}else{
    
    
				i = i - (j-1);
				j = 0;
			}
		}
		//判断是否匹配成功
		if(j == s2Len){
    
    
			return i - j;
		}else{
    
    
			return -1;
		}
	}
}

Introducción al algoritmo KMP

KMP es un algoritmo clásico para resolver si la cadena del patrón ha aparecido en la cadena de texto y, si ha aparecido, la posición de la primera aparición.

Antes de que se determine el algoritmo usando el método de KMP a través de la información a través de la siguiente matriz , se almacenó la longitud del patrón de cadena longitudinal de subsecuencia común más larga , cada vez que la matriz regresara para encontrar la siguiente, en el frente de la ubicación coincidente, eliminando la gran cantidad de tiempo de cálculo

Caso de estudio

Hay una cadena str1 = "BBC ABCDAB ABCDABCDABDE" y una subcadena str2 = "ABCDABD"

Ahora es necesario juzgar si str1 contiene str2, si existe, devolver la posición de la primera aparición, si no, devolver -1
Requisitos: Usar el algoritmo KMP para completar el juicio, no un simple algoritmo de coincidencia de fuerza bruta.

No escribiré el proceso de narración de texto. Después de todo, muchos tipos grandes lo escriben con mucha claridad. Si estás interesado aquí, puedes buscarlo. Publiqué un enlace a un anciano https://blog.csdn.net/ dark_cy / article / details / 88698736

package 字符串匹配问题;
import java.util.Arrays;
public class KMPAlgorithm {
    
    

	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		String str1 = "BBC ABCDAB ABCDABCDABDE";
		String str2 = "ABCDABD";
		
		int next[] = kmpNext("ABCDABD");  //[0,1]
		System.out.println("next"+Arrays.toString(next));
		int index = kmpSearch(str1, str2, next);
		System.out.println(index);
	}
	
	//获取到一个字符串(子串)的部分匹配值
	public static int[] kmpNext(String dest){
    
    
		//创建一个next数组保存部分匹配值
		int[] next = new int[dest.length()];
		next[0] = 0; //如果字符串是长度为1部分匹配值就是0
		for(int i = 1,j = 0;i < dest.length();i++){
    
    
			//当dest.charAt(i) != dest.charAt(j)
			//我们需要从next[j-1]获取新的j
			//知道我们发现有dest.charAt(i) == dest.charAt(j)成立才推出
			while(j > 0 && dest.charAt(i) != dest.charAt(j)){
    
    
				j = next[j-1];
			}
			//当dest.charAt(i) == dest.charAt(j)
			if(dest.charAt(i) == dest.charAt(j)){
    
    
				//部分匹配值就需要+1
				j++;
			}
			next[i] = j;
		}
		return next;
	}
	//写出KMP搜索算法
	/**
	 * 
	 * @param str1			原字符串
	 * @param str2			需要找的子串
	 * @param next			部分匹配表(子串对应的)
	 * @return				找到返回第一次出现的位置,没有匹配到返回-1
	 */
	public static int kmpSearch(String str1,String str2,int[] next){
    
    
		//遍历
		for (int i = 0,j = 0; i < str1.length(); i++) {
    
    
			//需要考虑不相等的情况    核心之处str1.charAt(i) != str2.charAt(j)
			while(j > 0 && str1.charAt(i) != str2.charAt(j)){
    
    
				j = next[j-1];
			}
			if(str1.charAt(i) == str2.charAt(j)){
    
    
				j++;
			}
			if(j == str2.length()){
    
    
				//找到了
				return i - j + 1;
			}
		}
		return -1;
	}
}

Comprensión personal

La dificultad del algoritmo KMP radica en esta parte del valor de coincidencia. Tienes que entenderlo por ti mismo. Los interesados ​​pueden buscar en Internet. Lo mismo que el método de coincidencia general es que cuando los caracteres son iguales, son todos se movieron hacia atrás. Continúe juzgando. La diferencia con el método de fuerza bruta es que cuando los dos caracteres no son iguales, la fuerza bruta es colocar la posición donde comenzamos a coincidir con la posición después del punto de partida , y luego continuar coincidir desde esta posición., será muy problemático, y el algoritmo KMP se basa en el valor de retorno de nuestro valor de coincidencia parcial para encontrarnos la ubicación de la revancha. Si comprende de dónde proviene este valor de coincidencia, también sabrá por qué desea trasladarse a esa ubicación . En general, el núcleo del algoritmo KMP se encuentra en el valor de coincidencia parcial y el siguiente código

		while(j > 0 && str1.charAt(i) != str2.charAt(j)){
    
    
			j = next[j-1];
		}

Es decir, cuando nuestra subcadena coincide con la posición donde el subíndice es mayor que 0, y el carácter con el subíndice i de la cadena original no es igual al carácter con la posición actual de la subcadena j, tenemos que volver a emparejar y esta posición es de El valor en nuestra tabla de coincidencia parcial se saca, es decir, la cadena original correspondiente a nuestra i ha ido hacia atrás, y no queríamos forzar el camino de regreso en una posición.

Supongo que te gusta

Origin blog.csdn.net/qq_22155255/article/details/113888417
Recomendado
Clasificación