Notas de algoritmo (1) - Preguntas de práctica de algoritmo KMP

contenido

1. Implementar strStr

2. Subcadenas repetidas 


1. Implementar strStr

Solución 1: Algoritmo de coincidencia de fuerza bruta (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;
    }
}

Solución 2: algoritmo 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 no comprende los puntos de conocimiento relevantes de la solución 1 y la solución 2, puede leer este blog para obtener una explicación detallada:

>>>Explicación detallada del algoritmo KMP

Solución 3: el hachís acelera la violencia

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

Solución cuatro:

Ideas para resolver problemas
1. Defina dos punteros, el puntero de la cabeza comienza desde la cabeza de la matriz del pajar y la posición del puntero de la cola está determinada por la longitud de la matriz de agujas, que es (0+len2-1)
2. Ingrese al ciclo while, la condición para el final del ciclo es El puntero de la cola llega al final de la matriz del pajar
3. Determine si la matriz del pajar comienza con la cabeza y la subcadena con len2 ya que la longitud es la misma que la matriz de la aguja .Si es así, devuelva el valor principal en este
momento.4.Haga la operación ++ en los punteros de cabeza y cola, mantenga el tamaño de ventana
5.El bucle finaliza, lo que significa que la coincidencia falla y devuelve -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;
    }
};

Solución 5: el uso de funciones de biblioteca de C++

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

Debería haber muchas soluciones a este problema, si se te ocurre puedes dejar un mensaje en el área de comentarios para discutirlo juntos.

2. Subcadenas repetidas 

Solución 1: algoritmo KMP

La siguiente es una solución KMP bien entendida que encontré en Likou

El método en el que la siguiente matriz no disminuye en uno y no se mueve. Consulte el
código para obtener más detalles . Se
recomienda encarecidamente que imprima la siguiente matriz y vea las reglas en la siguiente matriz, lo que le ayudará a comprender el Algoritmo KMP.

El juicio final si se puede entender de la siguiente manera:
si la respuesta es verdadera, los primeros dígitos (subcadenas) de la siguiente tabla son todos 0, y los siguientes se incrementarán todo el tiempo. Siguiente (n-1) almacena el original cadena menos el subcarácter. El valor de la longitud de la cadena se registra como len2, y el valor de len-len2 se registra como len1. len1 es la longitud de la subcadena, que debe ser divisible por 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;
}

Solución 2: método de enumeración

Ideas y Algoritmos

Si una cadena ss de longitud nn puede estar compuesta por una subcadena s's' de longitud n'n repetida muchas veces, entonces: nn debe ser un múltiplo de n'n'; s's' debe ser el prefijo de ss; para cualquier i \en [n', n)i∈[n ′ ,n), hay s[i] = s[in']s[i]=s[i−n ′]. Es decir, el prefijo de longitud n'n ' en ss es s's ', y el carácter s[i]s[i] en cada posición posterior debe ser el mismo que el carácter n'n-ésimo anterior. Los caracteres s[in']s[i−n ′ ] son ​​iguales. Por lo tanto, podemos enumerar n'n' de pequeño a grande y atravesar la cadena ss para hacer el juicio anterior. Tenga en cuenta que una pequeña optimización es que, dado que la subcadena debe repetirse al menos una vez, n'n ′ no será mayor que la mitad de nn, solo necesitamos estar en el rango [1, \frac{n}{2} ][1, 2n ] Basta enumerar 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;
}

Solución 3: Coincidencia de cadenas

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


 

 

 

Supongo que te gusta

Origin blog.csdn.net/m0_58367586/article/details/123094572
Recomendado
Clasificación