Notes sur l'algorithme (1) - Questions pratiques sur l'algorithme KMP

contenu

1. Implémenter strStr

2. Sous-chaînes répétées 


1. Implémenter strStr

Solution 1 : Algorithme de correspondance de force brute (BF)

int strStr(char * haystack, char * needle){
    assert(haystack!=NULL&&needle!=NULL);
    int len1=strlen(haystack);
    int len2=strlen(needle);
    int i=0,j=0;
    if(len2==0)
    {
        return 0;
    }
    if(len1==0&&len2!=0)
    {
        return -1;
    }
    while(i<len1&&j<len2)
    {
      if(haystack[i]==needle[j])
      {
          i++;
          j++;
      }
      else{
          i=i-j+1;
          j=0;
      }
    }
    if(j>=len2)
    {
        return i-j;
    }
    else{
        return -1;
    }
}

Solution 2 : Algorithme KMP

int strStr(char * haystack, char * needle){
    if(needle[0]=='\0')
    return 0;
      int len1=(int)strlen(haystack);
      int len2=(int)strlen(needle);
      int i=0;
      int j=0;
      int ans=-1;
      int* next=(int*)malloc(sizeof(int)*len2);
      getnext(next,needle);
      while(i<len1)
      {
          if(j==-1||haystack[i]==needle[j])
          {
             ++i;
              ++j;
          }
          else{
              j=next[j];
          }
          if(j==len2)
      {
          ans=i-len2;
          break;
      }
      }
      
          return ans;
}
void getnext(int next[],char* needle)
{
    next[0]=-1;
    int j=0;
    int k=-1;
    int len=(int)strlen(needle);
    while(j<len-1)
    {
        if(k==-1||needle[j]==needle[k])
        {
            ++j;
            ++k;
            next[j]=k;
        }
        else{
            k=next[k];
        }
    }

}

 Si vous ne comprenez pas les points de connaissance pertinents de la solution 1 et de la solution 2, vous pouvez lire ce blog pour une explication détaillée :

>>> Explication détaillée de l'algorithme KMP

Solution 3 : Le hachage accélère la violence

class Solution {
public:
    int strStr(string haystack, string needle) {
        if(needle=="") return 0;
        int n = haystack.size(), m = needle.size();
        int hash = 0;
        for(auto c: needle){
            hash += c -'a';
        }
        int cur = 0;
        for(int i = 0; i < n; i++){
            cur += haystack[i] - 'a';
            if(i >= m ) cur -= haystack[i-m] - 'a';
            if(i >= m-1 && cur == hash && haystack.substr(i-m+1,m) == needle)
                return i-m+1;
            
            
        }
        return -1;
    }
};

Solution 4 :

Idées de résolution de problèmes
1. Définissez deux pointeurs, le pointeur de tête commence à partir de la tête du tableau de la botte de foin et la position du pointeur de queue est déterminée par la longueur du tableau d'aiguilles, qui est (0+len2-1)
2. Entrez la boucle while, la condition pour la fin de la boucle est Le pointeur de queue atteint la fin du tableau haystack.
3. Déterminez si le tableau haystack commence par head et la sous-chaîne par len2 car la longueur est la même que celle du tableau needle . Si c'est le cas, renvoyez la valeur de tête à ce moment.
4. Effectuez l'opération ++ sur les pointeurs de tête et de queue, conservez la taille de fenêtre
5. La boucle se termine, ce qui signifie que la correspondance échoue, et renvoie -1

class Solution {
public:
    int strStr(string haystack, string needle) {
        int len1=haystack.size(),len2=needle.size();
        //尾指针的位置由needle数组的长度确定,也就是(0+len2-1)
        int head=0,tail=len2-1;
        //循环结束的条件是尾指针到达haystack数组的尾部
        while(tail<len1){
            //判断haystack数组以head为开头,len2为长度的子串和needle数组是否相同
            if(haystack.substr(head,len2)==needle) return head;
            head++;
            tail++;
        }
        return -1;
    }
};

Solution 5 : L'utilisation des fonctions de la bibliothèque C++

class Solution {
class Solution {
public:
    int strStr(string haystack, string needle) {
        if(needle.empty())
            return 0;
        int pos=haystack.find(needle);
        return pos;
    }
};

Il devrait y avoir plusieurs solutions à ce problème, si vous y pensez, vous pouvez laisser un message dans l'espace commentaire pour en discuter ensemble.

2. Sous-chaînes répétées 

Solution 1 : Algorithme KMP

Ce qui suit est une solution KMP bien comprise que j'ai trouvée à Likou

La méthode selon laquelle le tableau suivant ne diminue pas de un et ne bouge pas. Veuillez vous référer au
code pour plus de détails . Il est
fortement recommandé d'imprimer le tableau suivant et de voir les règles dans le tableau suivant, ce qui vous aidera à comprendre le Algorithme KMP.

Le jugement si final peut être compris comme suit :
si la réponse est vraie, les premiers chiffres (sous-chaînes) du tableau suivant sont tous 0, et les suivants seront incrémentés tout le temps. Suivant (n-1) stocke l'original chaîne moins le sous-caractère. La valeur de la longueur de la chaîne est enregistrée comme len2, et la valeur de len-len2 est enregistrée comme len1. len1 est la longueur de la sous-chaîne, qui doit être divisible par len !

 

//求字符串s的next数组
void Getnext(int *next, char *s, int len)
{
    int j=0;
    next[0]=0;
    for(int i=1; i<len; i++)
    {
        while(j>0 && s[i]!=s[j])
        {
            j=next[j-1];
        }
        if(s[i] == s[j])
        {
            j++;
        }
        next[i]=j;
    }
}

bool repeatedSubstringPattern(char * s)
{
    int len = strlen(s);
    if(len == 0) return false;
    int *next = (int*)malloc(sizeof(int) * len);

    Getnext(next, s, len);

    // next[len-1]!=0 代表s字符串有最长的相等前后缀
    // len % (len - next[len-1]) == 0 
    // 代表(数组长度 - 最长相等前后缀的长度)正好可以被数组的长度整除
    if(next[len-1]!=0 && len % (len - next[len-1]) == 0)
    {
        return true;
    }
    return false;
}

Solution 2 : Méthode d'énumération

Idées et algorithmes

Si une chaîne ss de longueur nn peut être composée d'une sous-chaîne s's' de longueur n'n répétée plusieurs fois, alors : nn doit être un multiple de n'n' ; s's' doit être le préfixe de ss ; for For any i \in [n', n)i∈[n ′ ,n), il y a s[i] = s[in']s[i]=s[i−n ′]. C'est-à-dire que le préfixe de longueur n'n ' dans ss est s's ', et le caractère s[i]s[i] à chaque position après doit être le même que le n'nième caractère avant lui Les caractères s[in']s[i−n ′ ] sont les mêmes. Par conséquent, nous pouvons énumérer n'n' de petit à grand et parcourir la chaîne ss pour faire le jugement ci-dessus. Notez qu'une petite optimisation est que puisque la sous-chaîne doit être répétée au moins une fois, n'n ′ ne sera pas supérieur à la moitié de nn, nous avons seulement besoin d'être dans l'intervalle [1, \frac{n}{2} ][1, 2n ] Il suffit d'énumérer n'n'.

bool repeatedSubstringPattern(char * s){
    int len=strlen(s);
   for(int i=1;i*2<=len;i++)
   {
       if(len%i==0){
       bool match=true;
       for(int j=i;j<len;j++)
       {
           if(s[j]==s[j-i])
           {
            match=true;
           }
           else{
               match=false;
               break;
           }
       }
       if(match==true)
       {
           return true;
       }
   }
   }
       return false;
}

Solution 3 : Correspondance de chaînes

bool repeatedSubstringPattern(char* s) {
    int n = strlen(s);
    char k[2 * n + 1];
    k[0] = 0;
    strcat(k, s);
    strcat(k, s);
    return strstr(k + 1, s) - k != n;
}


 

 

 

Je suppose que tu aimes

Origine blog.csdn.net/m0_58367586/article/details/123094572
conseillé
Classement