Algoritmo de coincidencia de cadenas [algoritmo de aprendizaje]

Prefacio

2023-8-6 12:06:42

El siguiente contenido es de "[Algoritmo de aprendizaje]"
y está destinado únicamente a fines de aprendizaje y comunicación.

derechos de autor

Elimine las siguientes palabras cuando publique en otras plataformas.
Este artículo se publicó por primera vez en la plataforma CSDN.
El autor es CSDN@日星月云.
La página de inicio del blog es https://blog.csdn.net/qq_51625007.
Elimine las siguientes palabras palabras anteriores al publicar en otras plataformas.

recomendar

28. Encuentra el subíndice de la primera coincidencia en una cadena.

Coincidencia de patrones de cuerdas


El contenido del conocimiento proviene del
Capítulo 4 Cadena (Estructura de datos y algoritmo)


La operación de posicionamiento de una subcadena es encontrar la posición donde la subcadena aparece por primera vez después del carácter pos en la cadena principal, también llamada "coincidencia de patrón de cadena" o "coincidencia de cadena", esta operación se usa ampliamente. Por ejemplo, en los programas de edición de texto, a menudo es necesario encontrar dónde aparece una palabra específica en el texto. Obviamente, los algoritmos efectivos para resolver este problema pueden mejorar en gran medida el rendimiento de respuesta de los programas de edición de texto. En la coincidencia de cadenas, la cadena principal S generalmente se denomina "cadena de destino" y la subcadena T se denomina "cadena de patrón".

Existen muchos algoritmos para la coincidencia de patrones. Este capítulo solo analiza dos algoritmos de coincidencia de cadenas, la coincidencia de patrones BF y la coincidencia de patrones KMP.

Algoritmo de coincidencia de patrones BF

[Idea del algoritmo BE]
El algoritmo de fuerza bruta, también conocido como algoritmo de "coincidencia de fuerza bruta" (conocido como algoritmo BP), comienza desde el carácter pos de la cadena principal S y lo compara con el primer carácter del patrón. cadena. Si son iguales, continúe comparando los caracteres siguientes uno por uno; de lo contrario, regrese al carácter pos+1 de la cadena principal y comience a compararlo con la cadena de patrón T nuevamente. Por analogía, hasta que cada carácter en la cadena del patrón sea igual a una secuencia de caracteres consecutiva en la cadena principal, se dice que la coincidencia del patrón es exitosa. En este momento, se devuelve el primer carácter de la cadena del patrón en la cadena principal S. .posición; de lo contrario, no hay una secuencia de caracteres igual a la cadena de patrón en la cadena principal y la coincidencia del patrón no tiene éxito.

[Descripción del algoritmo BF]
La estrategia para comparar la subcadena a partir del carácter pos-ésimo de la cadena principal S y la cadena de patrón T es compararlas secuencialmente de adelante hacia atrás. Por lo tanto, configurar el indicador i en la cadena principal indica el carácter actualmente comparado en la cadena principal S; configurar el indicador j en la cadena de patrón T indica el carácter actualmente comparado en la cadena de patrón T.

Como se muestra en la Figura 4-5, se proporciona un ejemplo del proceso de coincidencia, en el que los caracteres correspondientes al sombreado del cuadro no coinciden y no son iguales al comparar la cadena principal S y la cadena de patrón T (asumiendo pos=1). .

Compare el carácter pos-ésimo en la cadena principal S con el primer carácter de la cadena de patrón T. Si son iguales, continúe comparando los caracteres posteriores uno por uno. En este momento, i++;j++; de lo contrario, comience desde el siguiente El carácter de la cadena principal (i-j+2) se compara con el primer carácter (j=1) de la cadena del patrón y los detalles del análisis se muestran en la Figura 4-6(a).

Cuando la coincidencia es exitosa, se devuelve la posición del primer carácter en la cadena del patrón T en relación con la cadena principal (iT.en); de lo contrario, se devuelve 0. Para un análisis detallado, consulte la Figura 4-6(b), donde m es la longitud de la cadena del patrón T. .len.

int Index(SString S,int pos,SString T)
	int i=pos,j=1;//主串从第pos开始,模式串从头开始
	while (i<=S.len&&j<=T.len){
    
    
		if(S.ch[i]==T.ch[j]){
    
    //当对应字符相等时,比较后续字符
			i++;
			j++;
		}
		else{
    
    				//当对应字符不等时
			i=i-j+2;			//主串回溯到j-j+2的位置重新比较
			j=1;				//模式串从头开始重新比较
		}
	if(j>T.len)	return i-T.len;	//匹配成功时,返回匹配起始位置
	else return 0;				//匹配失败时,返回0

[Análisis del algoritmo BF]
La idea del algoritmo BF es relativamente simple, pero en el peor de los casos, la complejidad temporal del algoritmo es 0 (n × m), donde n y m son las longitudes de la cadena principal y el patrón respectivamente. . El principal consumo de tiempo de este algoritmo es el retroceso de la posición de comparación después de un desajuste, lo que resulta en demasiadas comparaciones. Para reducir la complejidad del tiempo, se puede utilizar un algoritmo sin retroceso.

Algoritmo de coincidencia de patrones KMP

[Idea del algoritmo KMP]
El algoritmo Knuth-Morris-Pratt (KMP para abreviar) es un algoritmo mejorado propuesto conjuntamente por DEKnuthJ.HMorris y V.RPratt. El algoritmo KMP es un algoritmo clásico en la coincidencia de patrones.En comparación con el algoritmo BF, la diferencia entre el algoritmo KMP es que elimina el retroceso del puntero S de la cadena principal i en el algoritmo BF. La complejidad temporal del algoritmo mejorado es 0 (n+m).

[Descripción del algoritmo KMP]
En el algoritmo KMP, siempre que los caracteres parecen ser desiguales en un proceso de coincidencia, el puntero en la cadena principal S no necesita retroceder, sino que utiliza el resultado de "coincidencia parcial" que se ha obtenido para mover el patrón. cadena hacia la derecha. Después de deslizarla lo más lejos posible, continúe la comparación.

Volviendo al ejemplo del proceso de comparación en la Figura 4-5, en la tercera coincidencia, cuando los caracteres i=7 y j=5 no son iguales, la comparación comienza nuevamente desde i=4.j=1. Sin embargo, después de una observación cuidadosa, se puede encontrar que las tres comparaciones en i=4 y j=1, i=5 y j=1, e i=6 y j=1 son innecesarias. Porque del tercer resultado de coincidencia parcial se puede concluir que los caracteres 4.º, 5.º y 6.º de la cadena principal deben ser iguales a los 2.3.4 caracteres de la cadena de patrón, es decir, todos son 'bca. Debido a que el primer carácter en la cadena del patrón es 'a', no es necesario compararlo con estos tres caracteres, solo necesita deslizar la cadena del patrón tres caracteres hacia la derecha para continuar i=7.j=2 Los caracteres pueden ser comparado. De la misma manera, cuando los caracteres no son iguales en la primera coincidencia, solo necesita mover el patrón dos caracteres hacia la derecha para comparar los caracteres cuando i=3 y j=1. Por lo tanto, durante todo el proceso de coincidencia, el puntero no retrocede, como se muestra en la Figura 4-7.

Insertar descripción de la imagen aquí

En términos generales, se supone que la cadena principal es 'S 1 S 2 ...S n ' y la cadena patrón es 'T 1 T 2 ...T n '. Del análisis del ejemplo anterior, podemos saber que para implementar el algoritmo KMP, es necesario resolver los siguientes problemas: Cuando el proceso de coincidencia Cuando ocurre una "no coincidencia" en la cadena del patrón (es decir, Si ≠ Ti) , la distancia de deslizamiento de la cadena del patrón "se desliza hacia el "derecha" está muy lejos. Es decir, cuando el carácter Si en la cadena principal y el carácter T j "en la cadena de patrón no coinciden ", qué carácter en la cadena de patrón debe compararse con el carácter Si en la cadena principal (el puntero i no retrocede) ?

Suponiendo que el carácter Si en la cadena principal debe continuar comparándose con el carácter T k (k <j) en el patrón en este momento, entonces la cadena principal S y la cadena del patrón T satisfacen la siguiente relación.
S=S 1 S 2 …S i-j+1 S i- j+2 …S i-k+1 …S i-1 S i …S n
T= T 1     T 2    …T j-k+1 … T j-k+2
T= T 1      …T k-1

Se puede ver que si 'T 1 T 2 ...T k-1 '='T j-k+1 T j-k+2 ...T j-1 ' existe en la cadena del patrón y satisface 1 <k<j, entonces, cuando j≠ TSi , solo necesita deslizar la cadena del patrón hacia la derecha hasta que el k-ésimo carácter esté alineado con el i-ésimo carácter en la cadena principal. para continuar con la comparación de Si y NokT Para "deslizarse" lo más posible durante el proceso de coincidencia, se debe seleccionar un valor k mayor que cumpla las condiciones.

Si siguiente [j] = k, entonces siguiente [] indica que cuando el j-ésimo carácter en el patrón "no coincide" con el carácter correspondiente en la cadena principal, la posición del carácter en el patrón debe compararse con el carácter en la cadena principal nuevamente. . Esto lleva a la definición de la siguiente función de la cadena del patrón:
Por favor agregue la descripción de la imagen.

Se puede ver que el cálculo de la siguiente función solo está relacionado con la cadena del patrón en sí y no tiene nada que ver con la cadena principal. Entre ellos, 'T 1 T 2 ...T k-1 ' es la verdadera subcadena de prefijo de 'T 1 T 2 ...T j-1 '', 'T j-k+1 T j-k+2 ...T j-1 ' Es la verdadera subcadena sufijo de 1 T 2 ...T j-1 '. Cuando el conjunto en la siguiente definición de función no está vacío, el valor de next[j] es igual a la longitud máxima de la subcadena + 1 cuando la subcadena de prefijo verdadera y la subcadena de sufijo verdadera de la cadena 'T 1 T 2 ...T j -1 ' son iguales .

A través del análisis anterior, el proceso de cálculo del siguiente valor de la cadena de patrón 'abaabcac' se deduce como se muestra en la Tabla 4.1.
(1) Cuando j=1, se sabe por la definición que next[1]=0;
(2) Cuando j=2, el valor k que satisface 1<k<j no existe, y se conoce por la definición que siguiente[2] =1

Por favor agregue la descripción de la imagen.

El siguiente valor de función de la cadena del patrón 'abaabcac' se muestra en la Figura 4-8.

Después de obtener la función de la cadena de patrón next, la coincidencia se puede realizar de la siguiente manera: suponga que los punteros iy jindican respectivamente los caracteres actualmente comparados en la cadena principal Sy la cadena de patrón , sea el valor inicial de be y el valor inicial de be. . Si S i = Ti durante el proceso de comparación , entonces la suma y la suma se incrementan respectivamente en 1; de lo contrario, permanecen sin cambios y las posiciones devueltas se comparan nuevamente (es decir, se comparan Si y T next[j] ) .Si son iguales, los punteros se incrementan en 1 respectivamente regresan a la posición del siguiente valor, y así sucesivamente, hasta las siguientes dos posibilidades: una es que cuando los caracteres sean iguales al regresar a un determinado valor ( ) , los punteros aumentarán en 1 para continuar coincidiendo; el otro es volver a 0 (es decir, "no coinciden" con el primer carácter del patrón), luego deberá deslizar tanto la cadena principal como la cadena del patrón una posición para hacia la derecha al mismo tiempo (j = 0 en este momento, al deslizar una posición hacia la derecha, es decir, el primer carácter de la cadena del patrón), es decir, la comparación comienza nuevamente de la cuerda principal y el patrón Ti . La Figura 4-9 es un ejemplo del proceso de coincidencia de KMP (asumiendo pos=1)Tiposj1ijijnext[j]jnextjnextnext[next[···next[j]]]jnext值

[Algoritmo 4-13] Algoritmo de coincidencia de patrones KMP

int Index_KMP( SString S, in pos, SString T){
    
    
	int i=pos,i=1;						//主串从第pos开始,模式事从头开始
	while(i<=S.len && j<=Tlen){
    
    
		if(j==0||S.ch[j]==T.ch[j]){
    
    		//继续比较后续宇符
			++i;++j;
		}else{
    
    
			j=next[j];					//模式申向右滑动
		}

if(j>T.len) return i-Tlen;				//匹配成功时,返回匹配的起始位置
else relurn 0							//匹配失败时,返回0

[Descripción del siguiente algoritmo]
El algoritmo KMP se ejecuta en función del siguiente valor de función conocido del patrón. Entonces, ¿cómo obtener el siguiente valor de función de la cadena del patrón?

Se puede ver en la definición que next[1]=0, suponiendo next[j]=k, esto muestra que hay 'T 1 T 2 ···T k-1 '='T j-k+1 T j-k en la cadena de patrón ···T j , tal relación, en la que el valor ken este momento next[j+1]puede tener las dos situaciones siguientes para satisfacer un cierto valor de 1<k<j.

(1) Si T j =T k , significa que en la cadena del patrón 'T 1 T 2 ···T k-1 '='T j-k+1 T j-k+2 ···T j '

T=T~1~ ··· T~j-k+1~	···	T~j-1~ T~j~ ··· T~m~
					   	        =
T=		    T~1~    ···	T~k-1~ T~k~···
			长度为k

Esto significa next[j+1]=k+1, es decir, next[j+1]=next[j]+1 .

(2) Si T j ≠T k , significa que en la cadena del patrón 'T 1 T 2 ···T k-1 '≠'T j-k+1 T j-k+2 ···T j '

En este momento, el problema de encontrar el valor de la siguiente función puede considerarse como un problema de coincidencia de patrones: toda la cadena del patrón es tanto la cadena principal como la cadena del patrón, donde 1 <k'<k <j.

T=T~1~ ··· T~j-k+1~	··· T~j-k'+1~ ···	T~j-1~ T~j~ ··· T~m~
					   	        ≠
T=		    T~1~    ···	T~k-k'+1~ ···   T~k-1~  T~k~ ···
T=					    T~1~     ···	T~k'-1~ T~k'-next[k]~

①Si T j =T k' y k'=next[k], entonces next[j+1]=k'+1 , es decir, next[j+1]=next[k]+1, que también es equivalente a siguiente [j+1]=siguiente[siguiente[j]]+1.
②Si T j ≠T k' , continúa comparando T j y T next[k'] , es decir, compara T j y T next[next[k]]
...
Luego sigue repitiendo, si hasta el último j=0 Si la comparación falla, entonces next[j+1]=1 .

A través del análisis anterior, al calcular el siguiente valor del carácter j + 1, es necesario ver si el carácter j es igual al carácter señalado por el siguiente valor del carácter j.

Se puede deducir que el siguiente proceso de cálculo del valor de la cadena patrón T=abaabcac es el siguiente.
①Cuando j = 1, se sabe por la definición que siguiente [1] = 0.

j=1
T=a
n=0

②Cuando j = 2, el valor que satisface 1 <h <j no existe, y el siguiente [2] = 1 se conoce por la definición.

j=12
T=ab
n=01

③Cuando j=3, dado que T 2 ≠ T 1 y el siguiente[1]=0, entonces el siguiente[3]=1.

j=12345678
T=abaabcac
n=011
T~2~ ≠ T~next[2]~	(T~1~)
T~2~ ? T~next[1]~	(0)
next[3]=1

④Cuando j=4, dado que T 3 =T 1 , siguiente[4]=siguiente[3]+1, es decir, siguiente[4]=2.

j=12345678
T=abaabcac
n=0112
  
T~3~ = T~next[3]~	(T~1~)
next[4]=next[3]+1

⑤Cuando j=5, dado que T 4 ≠ T 2 y el valor de next[2] es 1, continúe comparando T 4 y T 1. Dado que T 4 =T 1 , entonces next[5]=next[2] +1 , es decir, siguiente[5]=2.

j=12345678
T=abaabcac
n=01122
  
T~4~ ≠ T~next[4]~	(T~2~)
T~4~ = T~next[2]~	(T~1~)
next[5]=next[2]+1

⑥Cuando j=6, dado que T 5 =T 2 , entonces siguiente[6]=siguiente[5]+1, es decir, siguiente[6]=3.

j=12345678
T=abaabcac
n=011223
  
T~5~ = T~next[5]~	(T~2~)
next[6]=next[5]+1

⑦Cuando j = 7, dado que T 6 ≠ T 3 y el valor del siguiente [3] es 1, continúe comparando T 6 y T 1. Dado que T 6 ≠ T 1 y el siguiente [1] = 0, luego el siguiente [7] =1.

j=12345678
T=abaabcac
n=0112231
  
T~6~ ≠ T~next[6]~	(T~3~)
T~6~ ≠ T~next[3]~	(T~1~)
T~6~ ? T~next[1]~	(0)
next[7]=1

⑧Cuando j = 8, dado que T 7 = T 1 , entonces siguiente [8] = siguiente [7] +1, es decir, siguiente [8] = 2.

j=12345678
T=abaabcac
n=01122312
  
T~7~ = T~next[7]~	(T~1~)
next[8]=next[7]+1,

Por lo tanto, el siguiente valor de la cadena del patrón se obtiene como se muestra en la Figura 4-8.

j=12345678
T=abaabcac
n=01122312

[Algoritmo 4-14] siguiente algoritmo

void Get_Next( SString T, int next[]){
	int j=1,k=0;
	next[1]=0;
	while(j<T.len){
		if(k==0||T.ch[j]==Tch[k] ){
			++j;
			++k;
			nexi[j]=k;
		}else{
			k=next[k];
		}
	}
}

[descripción del algoritmo nextval]

La siguiente función definida anteriormente tiene fallas en algunos casos. Suponiendo que la cadena principal es 'aaabaaaab' y la cadena del patrón es 'aaaab', el siguiente valor de función correspondiente a la cadena del patrón es el siguiente.

Después de obtener el siguiente valor de la cadena del patrón, el proceso de coincidencia se muestra en la Figura 4-10(a).

Se puede ver en el proceso de coincidencia de cadenas que cuando i=4, j=4, S 4 no es igual a T 4 , como se muestra en next[j], i=4, j=3; i=4, j= 2; Tres comparaciones de i=4 y j=1. De hecho, debido a que el primer, segundo, tercer carácter y el cuarto carácter del patrón son todos iguales (es decir, todos son a), no es necesario compararlos con el cuarto carácter de la cadena principal, pero el patrón puede be Desliza 4 caracteres hacia la derecha para comparar directamente los caracteres de i=5 y j=1.

Es decir, si se obtiene next[j]=k de acuerdo con la definición anterior, y T j =T k en la cadena del patrón , entonces cuando Si T j , no hay necesidad de comparar Si y T k , y se compara directamente con T next [k] para comparar; en otras palabras, el valor de next [j] en este momento debe ser el mismo que next [k], por lo que next [j] se corrige a nextval [j]. Cuando T j ≠T k en la cadena de patrón , cuando Si ≠T j , aún es necesario realizar la comparación entre Si y T k, por lo que el valor de nextval[j] es k, es decir, el valor de nextval[j] es el siguiente valor [ j ].

A través del análisis anterior, al calcular el valor nextval del carácter j, depende de jsi el carácter señalado por el carácter j es igual al carácter señalado por el jcarácter j next. Si es igual, entonces nextval[j]=nextval[next[j]]; en caso contrario, nextval[j]=next[j]. De esto se puede deducir que el proceso de cálculo del valor nextval de la cadena de patrón T='aaaab' es el siguiente.

①Cuando j = 1, se sabe por la definición que nextval [1] = 0.
②Cuando j = 2, nex [2] = 1 y T 2 = T 1 , entonces nextval[2]=nextval[1], es decir nextval[2]=0.
③Cuando j=3, next[3]=2 y T 3 =T 2 , entonces nextval[3]=nextval[2], es decir, nextval[3]=0.
④Cuando j=4, next[4]=3 y T 4 =T 3 , entonces nextval[4]=nextval[3], es decir, nextval[4]=0.
⑤Cuando j=5, next[5]=4 y T 5 ≠ T 4 , entonces nextval[5]=next[5], es decir, nextval[5]=4.

El valor de la función nextal de la cadena de patrón 'aaaab' es el siguiente.

Después de obtener el valor nextval de la cadena del patrón, el proceso de coincidencia se muestra en la Figura 4-10 (b).

Hay dos formas de encontrar el valor de la función nextval. Una es encontrarlo directamente mediante observación sin depender del siguiente valor de la matriz. El otro método es inferir en función del siguiente valor de la matriz como se mencionó anteriormente. Aquí solo se presenta el segundo método. .

[Algoritmo 4-15] algoritmo nextval

void Get_NextVal(SString T, int next[ ] ,int nextval[ ]){
    
    
	int j=2,k=0;
	Get_Next(T,next);//通过算法4-14获得T的next值
	nextval[1]=0;	
	while (j<=T.len )
		k=next[j];
		if(T.ch[j]==T.ch[k]) nextval[j]=nextyal[ k];
		else nextval[j]=next[j];
		j++;
	}

[Análisis del algoritmo KMP]

El algoritmo KMP se ejecuta sobre la base del siguiente o siguiente valor de un patrón conocido. Si uno de ellos no se conoce, no hay forma de utilizar el algoritmo KMP. Aunque existen next y nextval, su significado y función son exactamente los mismos, por lo que cuando se conoce la coincidencia de next o nextval, el algoritmo de coincidencia permanece sin cambios.

Por lo general, la longitud m de la cadena del patrón es mucho menor que la longitud n de la cadena principal y la complejidad temporal de calcular la función next o nextval es 0 (m). Por lo tanto, el cálculo adicional de next o nextval vale la pena para todo el algoritmo de coincidencia.

La complejidad temporal del algoritmo BF es 0 (nxm), pero en la ejecución real, m suele ser mucho menor que n, por lo que es aproximadamente 0 (n + m), por lo que todavía se usa en la actualidad. El algoritmo KMP es más rápido que el algoritmo BF sólo cuando hay muchas "coincidencias parciales" entre la cadena del patrón y la cadena principal. La característica más importante del algoritmo KMP es que no es necesario rastrear el puntero de la cadena principal. Durante todo el proceso de coincidencia, la cadena principal solo necesita escanearse una vez de principio a fin. Es muy efectivo para procesar grandes cantidades. Entrada de archivos desde periféricos y se puede combinar durante la lectura.

libro de texto

práctica:

abaabcac
01122312

aaaab
01234

abaabcabc
011223123

ababcabaababb
0112312342345

abcabaa
0111232

abcaabbabcabaacbacba
01112231234532211211

El resultado es exactamente el mismo que el del libro de texto de idiomas.

import java.util.Arrays;

public class KMP0 {
    
    

    public static final int MAXLEN=50;

    static class SString{
    
    
        char[] ch=new char[MAXLEN+1];//0号单元不使用
        int len;

        public SString() {
    
    
        }

        public SString(char[] ch, int len) {
    
    
            this.ch = ch;
            this.len = len;
        }
    }

    public static void main(String[] args) {
    
    
//        test1();
        test2();

    }

    private static void test2() {
    
    
//        String t0="0abaabcac";
//        String t0="0abaabcabc";
        String t0="0aaaab";

        SString t=new SString(t0.toCharArray(),t0.length()-1);

        int[] next=new int[t.len+1];//0号也不使用
        get_next(t,next);

        System.out.println(Arrays.toString(next));

        int[] nextval=new int[t.len+1];//0号也不使用
        get_nextval(t,next,nextval);
        System.out.println(Arrays.toString(nextval));

    }


    private static void test1() {
    
    
        String s0="0aaabaaaab";
        String t0="0aaaab";
        SString s=new SString(s0.toCharArray(),s0.length()-1);
        SString t=new SString(t0.toCharArray(),t0.length()-1);

        int[] next=new int[t.len+1];//0号也不使用
        get_next(t,next);
        int i = index_kmp(s, 0, t,next);
        System.out.println(i);
    }


    public static int index_kmp(SString s,int pos,SString t,int[] next){
    
    
        int i=pos,j=1;
        while (i<=s.len&&j<=t.len){
    
    
            if (j==0||s.ch[i]==t.ch[j]){
    
    
                ++i;
                ++j;
            }else {
    
    
                j=next[j];
            }
        }
        if(j>t.len) return i-t.len;
        else return 0;
    }

    public static void get_next(SString t,int[] next){
    
    
        int j=1,k=0;
        next[1]=0;
        while (j<t.len){
    
    
            if(k==0||t.ch[j]==t.ch[k]){
    
    
                ++j;
                ++k;
                next[j]=k;
            }else{
    
    
                k=next[k];
            }
        }
    }

    public static void get_nextval(SString t,int[] next,int[] nextval){
    
    
        int j=2,k=0;
        get_next(t,next);
        nextval[1]=0;
        while (j<=t.len){
    
    
            k=next[j];
            if(t.ch[j]==t.ch[k]){
    
    
                nextval[j]=nextval[k];
            }else {
    
    
                nextval[j]=next[j];
            }
            j++;
        }
    }
}

Implementar algoritmos en Java

Solución oficial

class Solution {
    
    
    public int strStr(String haystack, String needle) {
    
    
        int n = haystack.length(), m = needle.length();
        if (m == 0) {
    
    
            return 0;
        }
        int[] pi = new int[m];
        for (int i = 1, j = 0; i < m; i++) {
    
    
            while (j > 0 && needle.charAt(i) != needle.charAt(j)) {
    
    
                j = pi[j - 1];
            }
            if (needle.charAt(i) == needle.charAt(j)) {
    
    
                j++;
            }
            pi[i] = j;
        }
        for (int i = 0, j = 0; i < n; i++) {
    
    
            while (j > 0 && haystack.charAt(i) != needle.charAt(j)) {
    
    
                j = pi[j - 1];
            }
            if (haystack.charAt(i) == needle.charAt(j)) {
    
    
                j++;
            }
            if (j == m) {
    
    
                return i - m + 1;
            }
        }
        return -1;
    }
}


Llamar a la API de Java

class Solution {
    
    
    public int strStr(String haystack, String needle) {
    
    
       return haystack.indexOf(needle);
    }
}

API de Java de referencia

Solo usa el algoritmo BF

class Solution {
    
    
    public static int strStr(String haystack, String needle) {
    
    
        char[] haystackValue=haystack.toCharArray();
        char[] needleValue=needle.toCharArray();
        return index(haystackValue,needleValue);
    }

    public static int index(char[] source, char[] target) {
    
    
        int sourceOffset=0;
        int targetOffset=0;
        int sourceCount=source.length;
        int targetCount=target.length;
        int max=sourceOffset+(sourceCount-targetCount);

        char first=target[targetOffset];

        for(int i=sourceOffset;i<=max;i++){
    
    
            //找第一个字符
            if (source[i] != first) {
    
    
                while (++i <= max && source[i] != first);
            }
            //匹配剩余的部分
            if(i<=max){
    
    
                int j=i+1;
                int end=j+targetCount-1;
                for (int k = targetOffset+1; j < end&&source[j]==target[k]; j++,k++);

                if(j==end){
    
    
                    return i-sourceOffset;
                }
            }
        }

        return -1;
    }
}

algoritmo BF

class Solution {
    
    
    public int strStr(String haystack, String needle) {
    
    
        return indexWithBF(haystack,0,needle);
    }

    public static int indexWithBF(String s,int pos,String t){
    
    
        int i=pos,j=0;//主串从pos开始,模式串从头开始
        while(i<s.length()&&j<t.length()){
    
    
            if(s.charAt(i)==t.charAt(j)){
    
    //当对应字符相等时,比较后续字符
                i++;
                j++;
            }else{
    
                          //对应字符不等时
                i=i-j+1;                //主串回溯到i-j+1的位置重写比较
                j=0;                    //模式串从头开始重写比较
            }
        }
        if(j>=t.length()) return i-t.length();  //匹配成功时,返回匹配起始位置
        else return -1;                         //匹配失败时,返回-1
    }
}

algoritmo KMP

class Solution {
    
    
    public int strStr(String haystack, String needle) {
    
    
        return indexWithKMP(haystack,0,needle);
    }

    public static int indexWithKMP(String s,int pos,String t){
    
    
        int[] next=next(t);

        int i=pos,j=0;                      //主串从pos开始,模式串从头开始
        while(i<s.length()&&j<t.length()){
    
    
            if(j==-1||s.charAt(i)==t.charAt(j)){
    
    //继续比较后续字符
                i++;
                j++;
            }else{
    
                          //模式串向右滑动
                j=next[j];
            }
        }
        if(j>=t.length()) return i-t.length();  //匹配成功时,返回匹配起始位置
        else return -1;                         //匹配失败时,返回-1
    }

    public static int[] next(String t){
    
    
        int len=t.length();
        int[] next=new int[len+1];
        int j=0,k=-1;
        next[0]=-1;
        while (j<len){
    
    
            if(k==-1||t.charAt(j)==t.charAt(k)){
    
    
                j++;
                k++;
                next[j]=k;
            }else{
    
    
                k=next[k];
            }
        }
        return next;
    }
}

Implementar algoritmo en C

algoritmo KMP

int strStr(char* haystack, char* needle) {
    
    
    int n = strlen(haystack), m = strlen(needle);
    if (m == 0) {
    
    
        return 0;
    }
    int pi[m];
    pi[0] = 0;
    for (int i = 1, j = 0; i < m; i++) {
    
    
        while (j > 0 && needle[i] != needle[j]) {
    
    
            j = pi[j - 1];
        }
        if (needle[i] == needle[j]) {
    
    
            j++;
        }
        pi[i] = j;
    }
    for (int i = 0, j = 0; i < n; i++) {
    
    
        while (j > 0 && haystack[i] != needle[j]) {
    
    
            j = pi[j - 1];
        }
        if (haystack[i] == needle[j]) {
    
    
            j++;
        }
        if (j == m) {
    
    
            return i - m + 1;
        }
    }
    return -1;
}

por fin

Todos tenemos un futuro brillante

Les deseo todo lo mejor en sus exámenes de ingreso a posgrado, les deseo todo el éxito
en su trabajo, deseo que todos obtengan lo que desean, den me gusta, recopilen y sigan.


Supongo que te gusta

Origin blog.csdn.net/qq_51625007/article/details/132129456
Recomendado
Clasificación