Algorithme de correspondance de chaînes [algorithme d'apprentissage]

Préface

2023-8-6 12:06:42

Le contenu suivant provient de « [Algorithme d'apprentissage] »
et est uniquement destiné à des fins d'apprentissage et de communication.

droits d'auteur

Supprimez les mots suivants lors de la publication sur d'autres plateformes.
Cet article a été publié pour la première fois sur la plateforme CSDN.
L'auteur est CSDN@日星月云.
La page d'accueil du blog est https://blog.csdn.net/qq_51625007.
Supprimez le au-dessus des mots lors de la publication sur d’autres plateformes.

recommander

28. Recherchez l'indice de la première correspondance dans une chaîne

Correspondance du modèle de chaîne


Le contenu des connaissances provient du
chapitre 4 String (Structure des données et algorithme)


L'opération de positionnement d'une sous-chaîne consiste à trouver la position où la sous-chaîne apparaît pour la première fois après le caractère pos dans la chaîne principale. Elle est également appelée « correspondance de modèle de chaîne » ou « correspondance de chaîne ». Cette opération est largement utilisée. Par exemple, dans les programmes d’édition de texte, il est souvent nécessaire de rechercher l’endroit où un mot spécifique apparaît dans le texte. De toute évidence, des algorithmes efficaces pour résoudre ce problème peuvent améliorer considérablement les performances de réponse des programmes d'édition de texte. Dans la correspondance de chaînes, la chaîne principale S est généralement appelée « chaîne cible » et la sous-chaîne T est appelée « chaîne de modèle ».

Il existe de nombreux algorithmes pour la correspondance de modèles. Ce chapitre traite uniquement de deux algorithmes de correspondance de chaînes, la correspondance de modèles BF et la correspondance de modèles KMP.

Algorithme de correspondance de modèles BF

[Idée d'algorithme BE]
L'algorithme Brute-Force, également connu sous le nom d'algorithme de « correspondance de force brute » (appelé algorithme BP), part du caractère pos de la chaîne principale S et le compare avec le premier caractère du motif. chaîne. S'ils sont égaux, continuez à comparer les caractères suivants un par un ; sinon, revenez au caractère pos+1 de la chaîne principale et recommencez à le comparer avec la chaîne de modèle T. Par analogie, jusqu'à ce que chaque caractère de la chaîne de modèle soit égal à une séquence de caractères consécutive dans la chaîne principale, on dit que la correspondance de modèle est réussie. À ce moment, le premier caractère de la chaîne de modèle dans la chaîne principale S est renvoyé . position ; sinon, il n'y a pas de séquence de caractères égale à la chaîne de modèle dans la chaîne principale et la correspondance de modèle échoue.

[Description de l'algorithme BF]
La stratégie pour comparer la sous-chaîne à partir du pos-ième caractère de la chaîne principale S et la chaîne de modèle T consiste à les comparer séquentiellement d'avant en arrière. Par conséquent, la définition de l'indicateur i dans la chaîne principale indique le caractère actuellement comparé dans la chaîne principale S ; la définition de l'indicateur j dans la chaîne de modèle T indique le caractère actuellement comparé dans la chaîne de modèle T.

Comme le montre la figure 4-5, un exemple de processus de correspondance est donné, dans lequel les caractères correspondant à l'ombrage de la boîte sont des caractères incompatibles qui ne sont pas égaux lors de la comparaison de la chaîne principale S et de la chaîne de modèle T (en supposant que pos=1). .

Comparez le pos-ième caractère de la chaîne principale S avec le premier caractère de la chaîne de modèle T. S'ils sont égaux, continuez à comparer les caractères suivants un par un. À ce stade, i++;j++ ; sinon, commencez par le suivant Le caractère de la chaîne principale (i-j+2 ) est comparé au premier caractère (j=1) de la chaîne de modèle, et les détails de l'analyse sont présentés dans la figure 4-6(a).

Lorsque la correspondance est réussie, la position du premier caractère de la chaîne de modèle T par rapport à la chaîne principale (iT.en) est renvoyée ; sinon, la valeur 0 est renvoyée. Pour une analyse détaillée, voir la figure 4-6(b), où m est la longueur de la chaîne de motif 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

[Analyse de l'algorithme BF]
L'idée de l'algorithme BF est relativement simple, mais dans le pire des cas, la complexité temporelle de l'algorithme est de 0 (n × m), où n et m sont respectivement les longueurs de la chaîne principale et du motif. . La principale consommation de temps de cet algorithme est le retour en arrière de la position de comparaison après une disparité, ce qui entraîne un trop grand nombre de comparaisons. Afin de réduire la complexité temporelle, un algorithme sans retour en arrière peut être utilisé.

Algorithme de correspondance de modèles KMP

[Idée d'algorithme KMP]
L'algorithme de Knuth-Morris-Pratt (KMP en abrégé) est un algorithme amélioré proposé conjointement par DEKnuthJ.HMorris et V.RPratt. L'algorithme KMP est un algorithme classique de correspondance de modèles. Par rapport à l'algorithme BF, la différence de l'algorithme KMP est qu'il élimine le retour en arrière du pointeur i de la chaîne principale S dans l'algorithme BF. La complexité temporelle de l'algorithme amélioré est de 0(n+m).

[Description de l'algorithme KMP]
Dans l'algorithme KMP, chaque fois que des caractères semblent inégaux dans un processus de correspondance, le pointeur dans la chaîne principale S n'a pas besoin de revenir en arrière, mais utilise le résultat de « correspondance partielle » qui a été obtenu pour déplacer le motif. chaîne vers la droite. Après l’avoir glissée le plus loin possible, continuez la comparaison.

En repensant à l'exemple du processus de correspondance de la figure 4-5, lors de la troisième correspondance, lorsque les caractères i=7 et j=5 ne sont pas égaux, la comparaison recommence à partir de i=4.j=1. Cependant, après une observation attentive, on peut constater que les trois comparaisons à i=4 et j=1, i=5 et j=1, et i=6 et j=1 sont inutiles. Parce qu'on peut conclure du troisième résultat de correspondance partielle que les 4ème, 5ème et 6ème caractères de la chaîne principale doivent être égaux aux 2.3.4 caractères de la chaîne de modèle, c'est-à-dire qu'ils sont tous 'bca. Étant donné que le premier caractère de la chaîne de modèle est « a », il n'est pas nécessaire de le comparer à ces trois caractères, mais il suffit de faire glisser la chaîne de modèle de trois caractères vers la droite pour continuer. i=7.j=2 Les caractères peuvent être comparé. De la même manière, lorsque les caractères ne sont pas égaux lors de la première correspondance, il suffit de déplacer le motif vers la droite de deux caractères pour comparer les caractères lorsque i=3 et j=1. Par conséquent, pendant tout le processus de correspondance, le pointeur ne revient pas en arrière, comme le montre la figure 4-7.

Insérer la description de l'image ici

D'une manière générale, on suppose que la chaîne principale est 'S 1 S 2 ...S n ' et que la chaîne de modèle est 'T 1 T 2 ...T n '. À partir de l'analyse de l'exemple ci-dessus, nous pouvons savoir que pour mettre en œuvre l'algorithme KMP, les problèmes suivants doivent être résolus : Lorsque le processus de correspondance Lorsqu'une « incompatibilité » se produit dans la chaîne de modèle (c'est-à-dire Si ≠ T i ), la distance de glissement de la chaîne de modèle « glisse vers le right" est très loin. C'est-à-dire que lorsque le caractère Si dans la chaîne principale et le caractère T j " dans la chaîne de modèle ne correspondent pas lors de la correspondance ", quel caractère de la chaîne de modèle doit être comparé au caractère Si dans la chaîne de modèle. chaîne principale (le pointeur i ne revient pas en arrière) ?

En supposant que le caractère Si dans la chaîne principale doit continuer à être comparé au caractère Tk (k<j) dans le modèle à ce moment, alors la chaîne principale S et la chaîne de modèle T satisfont la relation suivante.
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

On peut voir que si 'T 1 T 2 ...T k-1 '='T j-k+1 T j-k+2 ...T j-1 ' existe dans la chaîne de modèle et satisfait 1 <k<j, alors Lorsque j≠TSi , il vous suffit de faire glisser la chaîne de motif vers la droite jusqu'à ce que le k-ème caractère soit aligné avec le i-ème caractère de la chaîne principale. pour continuer la comparaison de Si et .Tk Afin de « glisser » le plus loin possible pendant le processus d'appariement, une valeur k plus grande qui remplit les conditions doit être sélectionnée.

Si next[j]=k, alors next[] indique que lorsque le j-ème caractère du modèle "ne correspond pas" au caractère correspondant dans la chaîne principale, la position du caractère dans le modèle doit être comparée au caractère à nouveau dans la chaîne principale. . Cela conduit à la définition de la fonction suivante de la chaîne de modèle :
Veuillez ajouter une description de l'image

On peut voir que le calcul de la fonction suivante n'est lié qu'à la chaîne de modèle elle-même et n'a rien à voir avec la chaîne principale. Parmi eux, 'T 1 T 2 ...T k-1 ' est la véritable sous-chaîne de préfixe de 'T 1 T 2 ...T j-1 ', 'T j-k+1 T j-k+2 ...T j-1 ' Est la véritable sous-chaîne de suffixe de 1 T 2 ...T j-1 '. Lorsque l'ensemble dans la définition de fonction suivante n'est pas vide, la valeur de next[j] est égale à la longueur maximale de la sous-chaîne + 1 lorsque la vraie sous-chaîne de préfixe et la vraie sous-chaîne de suffixe de la chaîne 'T 1 T 2 ...T j -1 ' sont égaux .

Grâce à l'analyse ci-dessus, le processus de calcul de la valeur suivante de la chaîne de modèle « abaabcac » est déduit comme indiqué dans le tableau 4.1.
(1) Lorsque j=1, on sait d'après la définition que next[1]=0 ;
(2) Quand j=2, la valeur k qui satisfait 1<k<j n'existe pas, et elle est connue d'après la définition que next[2] =1

Veuillez ajouter une description de l'image

La valeur de fonction suivante de la chaîne de modèle « abaabcac » est illustrée à la figure 4-8.

Après avoir obtenu la fonction de la chaîne de modèle next, la correspondance peut être effectuée comme suit : Supposons que les pointeurs iet jindiquent respectivement les caractères actuellement comparés dans la chaîne principale Set la chaîne de modèle , soit la valeur initiale de be et la valeur initiale de be . Si S i = T i pendant le processus d'appariement , alors les sommes sont augmentées de 1 respectivement ; sinon, elles restent inchangées et les positions renvoyées sont à nouveau comparées (c'est-à-dire que Si et T next[j] sont comparés). sont égaux, les pointeurs augmentent respectivement de 1, sinon reviennent à la position de la valeur suivante, et ainsi de suite, jusqu'aux deux possibilités suivantes : l'une est que lorsque les caractères sont égaux en revenant à une certaine valeur ( ), les pointeurs augmentera de 1 pour continuer la correspondance ; l'autre consiste à revenir à 0 (c'est-à-dire "incompatibilité" avec le premier caractère du motif), vous devez alors faire glisser à la fois la chaîne principale et la chaîne du motif d'une position vers la droite à en même temps (j=0 à ce moment-là, en glissant une position vers le bon moment, c'est-à-dire le premier caractère de la chaîne de motif), c'est-à-dire que la comparaison recommence principale et le motif Ti . La figure 4-9 est un exemple du processus de correspondance KMP (en supposant que pos=1)Tiposj1ijijnext[j]jnextjnextnext[next[···next[j]]]jnext值

[Algorithme 4-13]Algorithme de correspondance de modèles 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

[Description de l'algorithme suivant]
L'algorithme KMP est exécuté sur la base de la valeur de fonction suivante connue du modèle. Alors, comment obtenir la valeur de fonction suivante de la chaîne de modèle ?

On peut voir à partir de la définition que next[1]=0, en supposant next[j]=k, cela montre qu'il existe 'T 1 T 2 ···T k-1 '='T j-k+1 T j-k dans la chaîne de modèle ···T j , une telle relation, dans laquelle la valeur kà ce moment next[j+1]peut avoir les deux situations suivantes pour satisfaire une certaine valeur de 1<k<j.

(1) Si T j =T k , cela signifie que dans la chaîne de motif '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

Cela signifie next[j+1]=k+1, c'est-à-dire next[j+1]=next[j]+1 .

(2) Si T j ≠T k , cela signifie que dans la chaîne de motif 'T 1 T 2 ···T k-1 '≠'T j-k+1 T j-k+2 ···T j '

À l'heure actuelle, le problème de trouver la valeur de la fonction suivante peut être considéré comme un problème de correspondance de modèles.La chaîne de modèle entière est à la fois la chaîne principale et la chaîne de modèle, où 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' , et k'=next[k], alors next[j+1]=k'+1 , c'est-à-dire next[j+1]=next[k]+1, qui est également équivalent à suivant [j+1]=suivant[suivant[j]]+1.
②Si T j ≠T k' , continuez à comparer T j et T next[k'] , c'est-à-dire comparez T j et T next[next[k]]
...
Puis continuez à répéter, si jusqu'au dernier j=0 Si la comparaison échoue, alors next[j+1]=1 .

Grâce à l'analyse ci-dessus, lors du calcul de la valeur suivante du j+1ème caractère, il est nécessaire de voir si le jème caractère est égal au caractère pointé par la valeur suivante du jème caractère.

On peut en déduire que le prochain processus de calcul de la valeur de la chaîne de modèle T=abaabcac est le suivant.
①Quand j=1, on sait d'après la définition que next[1]=0.

j=1
T=a
n=0

②Quand j=2, la valeur satisfaisant 1<h<j n'existe pas et next[2]=1 est connu à partir de la définition.

j=12
T=ab
n=01

③Quand j=3, puisque T 2 ≠ T 1 et next[1]=0, alors next[3]=1.

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

④Quand j=4, puisque T 3 =T 1 , next[4]=next[3]+1, c'est-à-dire next[4]=2.

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

⑤Lorsque j=5, puisque T 4 ≠ T 2 et que la valeur de next[2] est 1, continuez à comparer T 4 et T 1. Puisque T 4 =T 1 , alors next[5]=next[2] +1 , c'est-à-dire next[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

⑥Quand j=6, puisque T 5 =T 2 , alors next[6]=next[5]+1, c'est-à-dire next[6]=3.

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

⑦Lorsque j=7, puisque T 6 ≠T 3 et que la valeur de next[3] est 1, continuez à comparer T 6 et T 1. Puisque T 6 ≠ T 1 et next[1]=0, alors next [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

⑧Quand j=8, puisque T 7 =T 1 , alors next[8]=next[7]+1, c'est-à-dire next[8]=2.

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

Par conséquent, la valeur suivante de la chaîne de modèle est obtenue comme le montre la figure 4-8.

j=12345678
T=abaabcac
n=01122312

[Algorithme 4-14] algorithme suivant

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];
		}
	}
}

[description de l'algorithme nextval]

La fonction suivante définie ci-dessus présente des défauts dans certains cas. En supposant que la chaîne principale est « aaabaaaab » et que la chaîne de modèle est « aaaab », la valeur de fonction suivante correspondant à la chaîne de modèle est la suivante.

Après avoir obtenu la valeur suivante de la chaîne de modèle, le processus de correspondance est illustré à la figure 4-10(a).

Il ressort du processus de correspondance de chaînes que lorsque i=4, j=4, S 4 n'est pas égal à T 4 , comme le montre next[j], i=4, j=3 ; i=4, j= 2 ; Trois comparaisons de i=4 et j=1. En fait, comme les 1er, 2e, 3e caractères et le 4e caractère du motif sont tous égaux (c'est-à-dire qu'ils sont tous des a), il n'est pas nécessaire de comparer avec le 4e caractère de la chaîne principale, mais le motif peut be Faites glisser 4 caractères vers la droite pour comparer directement les caractères de i=5 et j=1.

C'est-à-dire que si next[j]=k est obtenu selon la définition ci-dessus, et T j =T k dans la chaîne de motifs , alors lorsque Si T j , il n'est pas nécessaire de comparer Si et T k , et il est directement comparé à T next [k] pour comparaison ; en d'autres termes, la valeur de next[j] à ce moment doit être la même que celle de next[k], donc next[j] est corrigé en nextval[j]. Lorsque T j ≠T k dans la chaîne de modèle , lorsque Si ≠T j , la comparaison entre Si et T k doit encore être effectuée, donc la valeur de nextval[j] est k, c'est-à-dire la valeur de nextval[j] est la prochaine valeur [ j ].

Grâce à l'analyse ci-dessus, lors du calcul de la valeur nextval du jème caractère, cela dépend jsi le caractère pointé par le jème caractère est égal au caractère pointé par le jjème caractère next. Si égal, alors nextval[j]=nextval[next[j]]; sinon, nextval[j]=next[j]. De cela, on peut en déduire que le processus de calcul de la valeur suivante de la chaîne de modèle T='aaaab' est le suivant.

①Quand j=1, on sait d'après la définition que nextval[1]=0.
②Quand j=2, nex[2]=1 et T 2 =T 1 , alors nextval[2]=nextval[1], c'est-à-dire nextval[2]=0.
③Quand j=3, next[3]=2 et T 3 =T 2 , alors nextval[3]=nextval[2], c'est-à-dire nextval[3]=0.
④Quand j=4, next[4]=3 et T 4 =T 3 , alors nextval[4]=nextval[3], c'est-à-dire nextval[4]=0.
⑤Quand j=5, next[5]=4 et T 5 ≠ T 4 , alors nextval[5]=next[5], c'est-à-dire nextval[5]=4.

La valeur de fonction suivante de la chaîne de modèle « aaaab » est la suivante.

Après avoir obtenu la valeur nextval de la chaîne de modèle, le processus de correspondance est illustré à la figure 4-10(b).

Il existe deux manières de trouver la valeur de la fonction nextval. L'une consiste à la trouver directement par observation sans s'appuyer sur la valeur suivante du tableau. L'autre méthode consiste à déduire en fonction de la valeur suivante du tableau, comme mentionné ci-dessus. Seule la deuxième méthode est présentée ici. .

[Algorithme 4-15] algorithme 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++;
	}

[Analyse de l'algorithme KMP]

L'algorithme KMP est exécuté sur la base du next ou nextval d'un modèle connu. Si l'un d'eux n'est pas connu, il n'y a aucun moyen d'utiliser l'algorithme KMP. Bien qu'il existe next et nextval, leur signification et leur fonction sont exactement les mêmes, donc lorsque la correspondance next ou nextval est connue, l'algorithme de correspondance reste inchangé.

Habituellement, la longueur m de la chaîne de modèle est beaucoup plus petite que la longueur n de la chaîne principale et la complexité temporelle du calcul de la fonction next ou nextval est de 0(m). Par conséquent, le calcul supplémentaire de next ou nextval vaut la peine pour l’ensemble de l’algorithme de correspondance.

La complexité temporelle de l'algorithme BF est de 0(nxm), mais dans l'exécution réelle, m est souvent beaucoup plus petit que n, il est donc d'environ 0(n+m), il est donc toujours utilisé aujourd'hui. L'algorithme KMP est plus rapide que l'algorithme BF uniquement lorsqu'il existe de nombreuses « correspondances partielles » entre la chaîne de modèle et la chaîne principale. La plus grande caractéristique de l'algorithme KMP est qu'il n'est pas nécessaire de retracer le pointeur de la chaîne principale. Pendant tout le processus de correspondance, la chaîne principale ne doit être analysée qu'une seule fois, du début à la fin. Il est très efficace pour traiter d'énormes fichiers entrés à partir de périphériques et peuvent être mis en correspondance pendant la lecture.

cahier de texte

pratique:

abaabcac
01122312

aaaab
01234

abaabcabc
011223123

ababcabaababb
0112312342345

abcabaa
0111232

abcaabbabcabaacbacba
01112231234532211211

Le résultat est exactement le même que celui du manuel de langue

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++;
        }
    }
}

Implémenter des algorithmes en Java

Solution officielle

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;
    }
}


Appeler l'API Java

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

API Java de référence

Utilisez simplement l'algorithme 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;
    }
}

Algorithme 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
    }
}

Algorithme 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;
    }
}

Implémenter un algorithme en C

Algorithme 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;
}

enfin

Nous avons tous un avenir brillant

Je vous souhaite tout le meilleur pour vos examens d'entrée de troisième cycle, je vous souhaite à tous du succès
dans votre travail, je vous souhaite à tous d'obtenir ce que vous souhaitez, d'aimer, de collectionner et de suivre.


Je suppose que tu aimes

Origine blog.csdn.net/qq_51625007/article/details/132129456
conseillé
Classement