Distancia máxima de Hamming entre una lista de cuerdas acolchadas

18

La distancia de Hamming entre dos cadenas de igual longitud es el número de posiciones en las que los caracteres correspondientes son diferentes. Si las cadenas no tienen la misma longitud, la distancia de Hamming no está definida.

Desafío

Escriba un programa o función que encuentre la mayor distancia de Hamming entre todos los pares de cadenas de una lista de cadenas, rellenada según sea necesario de acuerdo con las reglas que se describen a continuación.

Los personajes serán de dentro a-zA-Z0-9.

Las cadenas pueden no tener la misma longitud, por lo que para cada comparación, la cadena más corta debe rellenarse de la siguiente manera:

  • envuelva la cadena desde el principio tantas veces como sea necesario para que coincida con la longitud requerida
  • cambiar los casos de las letras cada vez que se envuelve (1er, 3er, 5to, etc.)
  • dejar las cosas afuera a-zA-Zsin cambios al envolver

Por ejemplo, supongamos que necesita rellenar la cadena de 5 caracteres ab9Cdpara que termine con 18 caracteres. Terminarías con:

ab9CdAB9cDab9CdAB9
     ^^^^^     ^^^

con ^agregado debajo de la 1ra y 3ra envolturas para resaltar los cambios de caso.

De entrada y salida

El formato de entrada / salida es flexible. Puede suponer que la entrada tiene al menos dos cadenas y que todas las cadenas tendrán al menos un carácter.

La salida es un entero.

Reglas

Este es el . Aplican reglas estándar.

Casos de prueba

[ "a", "b" ] => 1
[ "a", "b", "c" ] => 1
[ "a", "a", "c" ] => 1
[ "abc", "abcd" ] => 1
[ "abc12D5", "abC34d3", "ABC14dabc23DAbC89d"] => 17  
[ "a", "Aaa", "AaaA", "aAaAa", "aaaaaaaaaaaaaa", "AAaAA", "aAa" ] => 8
["AacaAc", "Aab"] => 2

Implementación de referencia

Probé los ejemplos con un código R (completamente no protegido) que puedes probar aquí para comparar cualquier otro ejemplo que puedas probar con tu código.

ngm
fuente
1
cambiar las mayúsculas y minúsculas de las letras cada vez que se envuelve - Oh, chico, este requisito será un dolor para mi solución ... Sin embargo, me gusta el desafío, así que +1
Sr. Xcoder
Caso de prueba sugerida: ["AacaAc", "Aab"] => 2. Un golf intencionado para mi respuesta de Jelly hubiera fallado en ese caso, pero habría pasado todos los demás.
Sr. Xcoder
@ngm ¡Excelente desafío! +1
Don Thousand

Respuestas:

7

Jalea , 20 bytes

No muy contento con eso. Debería ser golfable, incluso a ~ 15 bytes tal vez.

LÞŒcµṁ/sḢL$ŒsÐeFn)§Ṁ

Pruébalo en línea!

o echa un vistazo a una suite de prueba!

Explicación

LÞŒcµṁ / sḢL $ ŒsÐeFn) §Ṁ Programa completo o enlace monádico. N = entrada. El | Ejemplo: ["abc12D5", "abC34d3", "ABC14dabc23DAbC89d"]
LÞ Ordenar N por longitud. El | [['a', 'b', 'c', '1', '2', 'D', '5'], ['a', 'b', 'C', '3', '4 ',' d ',' 3 '], [' A ',' B ',' C ',' 1 ',' 4 ',' d ',' a ',' b ',' c ',' 2 ',' 3 ',' D ',' A ',' b ',' C ',' 8 ',' 9 ',' d ']] (en Jelly, las cadenas son una lista de caracteres)
  Œc Pares desordenados: [x, y] para todos los distintos x, y en N. | [[['' ',' b ',' c ',' 1 ',' 2 ',' D ',' 5 '], [' a ',' b ',' C ',' 3 ',' 4 ',' d ',' 3 ']], [[' 'a', 'b', 'c', '1', '2', 'D', '5'], ['A', ' B ',' C ',' 1 ',' 4 ',' d ',' a ',' b ',' c ',' 2 ',' 3 ',' D ',' A ',' b ' , 'C', '8', '9', 'd']], [['' a ',' b ',' C ',' 3 ',' 4 ',' d ',' 3 '], ['A', 'B', 'C', '1', '4', 'd', 'a', 'b', 'c', '2', '3', 'D',
                        Aquí, por distinto, quiero decir en diferentes posiciones. El |
    µ) Mapa con un enlace monádico. El |
     ṁ / Molde x como y. Es decir, ciclo x hasta que alcance la longitud y. El | [['a', 'b', 'c', '1', '2', 'D', '5'], ['a', 'b', 'c', '1', '2 ',' D ',' 5 ',' a ',' b ',' c ',' 1 ',' 2 ',' D ',' 5 ',' a ',' b ',' c ', '1'], ['a', 'b', 'C', '3', '4', 'd', '3', 'a', 'b', 'C', '3', '4', 'd', '3', 'a', 'b', 'C', '3']]
       sḢL $ Dividir en trozos de la longitud de x. El | [[['' a ',' b ',' c ',' 1 ',' 2 ',' D ',' 5 ']], [[' 'a', 'b', 'c', '1' , '2', 'D', '5'], ['a', 'b', 'c', '1', '2', 'D', '5'], ['a', ' b ',' c ',' 1 ']], [[' 'a', 'b', 'C', '3', '4', 'd', '3'], ['a', ' b ',' C ',' 3 ',' 4 ',' d ',' 3 '], [' a ',' b ',' C ',' 3 ']]]
           ŒsÐe Cambia el caso de fragmentos indexados pares (1 indexado). El | [[['' a ',' b ',' c ',' 1 ',' 2 ',' D ',' 5 ']], [[' 'a', 'b', 'c', '1' , '2', 'D', '5'], ['A', 'B', 'C', '1', '2', 'd', '5'], ['a', ' b ',' c ',' 1 ']], [[' 'a', 'b', 'C', '3', '4', 'd', '3'], ['A', ' B ',' c ',' 3 ',' 4 ',' D ',' 3 '], [' a ',' b ',' C ',' 3 ']]]
               F Acoplar. El | [['a', 'b', 'c', '1', '2', 'D', '5'], ['a', 'b', 'c', '1', '2 ',' D ',' 5 ',' A ',' B ',' C ',' 1 ',' 2 ',' d ',' 5 ',' a ',' b ',' c ', '1'], ['a', 'b', 'C', '3', '4', 'd', '3', 'A', 'B', 'c', '3', '4', 'D', '3', 'a', 'b', 'C', '3']]
                n Desigualdad vectorizada con y. El | [[[0, 0, 1, 1, 1, 1, 1]], [[1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 , 1, 1, 1]], [[1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1]]]
                  § Después de terminar el mapa, suma cada matriz bool (0 o 1). El | [[5], [17], [14]]
                   Ṁ Máximo. El | 17
Sr. Xcoder
fuente
No estoy totalmente familiarizado con Jelly, pero creo que puedes omitir y seguir obteniendo el mismo máximo al final.
Chas Brown
@ChasBrown Ugh, no, debería necesitar eso. De lo contrario, en lugar de rellenar el más corto a la longitud del más largo, en ṁ/cambio recortaría el más largo a la longitud del más corto en algunos casos, que no es lo que queremos ... Supongo que los casos de prueba están demasiado bien elegidos (y esta es una coincidencia bastante desafortunada) ...
Sr. Xcoder
@ChasBrown Como ejemplo, intente ["AacaAc", "Aab"].
Sr. Xcoder
Ah sí, ya veo ... necesito aprender más Jelly ... :)
Chas Brown
5

Python 2 , 86 bytes

lambda a:max(sum(x!=y for x,y in zip((s+s.swapcase())*len(t),t))for s in a for t in a)

Pruébalo en línea!

Dadas dos secuencias, s,t, zip((s+s.swapcase())*len(t),t))será una lista de tuplas de longitud len(t)desde ziptrunca a la más corta iterable. Si len(s)<len(t), entonces esto "se rellena" scon el intercambio de mayúsculas y minúsculas y calculamos los sumdiferentes caracteres.

Si len(t)<=len(s), entonces el resultado sumserá menor o igual que sumsi estuviéramos evaluando t,s; por lo que no tiene ningún efecto en el resultado maxen ese caso.

Chas Brown
fuente
Puede usar en y!=lugar de !=yguardar 1 byte
Mr. Xcoder
@Señor. Xcoder: Thx, pero terminé reelaborando drásticamente mi solución ...
Chas Brown
3

Jalea , 19 bytes

WṁŒsÐeF=ċ0
LÞŒcç/€Ṁ

Pruébalo en línea!

LÞŒcç/€Ṁ
LÞ         Sort by length
  Œc       unordered pairs
      €    to each of the pairs
    ç/     find the hamming distance with molding and swapping case (helper link)
       Ṁ   maximum

WṁŒsÐeF=ċ0
W            wrap the shorter string
 ṁ           repeat this string once for each character in the second string
    Ðe       for every other repeated string
  Œs         swap case
      F      flatten
       =     characterwise equality check between the two strings. If the first
             string is longer, the leftover characters are appended to the result.
             e.g. 'abABab' and 'xbA' give [0,1,1,'B','a','b']
        ċ0   count the number of 0s, giving the Hamming distance.
dylnan
fuente
2

Ruby , 89 82 bytes

Crea el producto cruzado de la lista de entrada contra sí mismo antes de calcular la distancia de Hamming de cada par, utilizando un método de duplicación similar a la respuesta de Chas Brown . Sin embargo, Ruby no puede juntar cadenas o agregar booleanos sin sobrecarga adicional, por lo que se hace necesario iterar manualmente a través del par de cadenas.

-7 bytes de GB.

->a{a.product(a).map{|s,t|(0...w=t.size).count{|i|(s+s.swapcase)[i%w]!=t[i]}}.max}

Pruébalo en línea!

Tinta de valor
fuente
1
82 bytes
GB
2

Java 10 ,748 740 667 666 616 bytes

Este tiene que ser el más denso e ilegible, sin embargo, el golf más largo que se me ocurrió.

Método de llamada h(String[])con una matriz explícita (sin argumentos var): por ejemplo,

h(new String[] {"a", "b", "c"});

vuelve 1.

char e(boolean w,char c){return(char)(w&(64<c&c<91|96<c&c<123)?c^32:c);}String p(String s,int l){var p="";int m=s.length(),n=l/m,r=l%m,i=0,j=0;var w=1<0;for(;i<n;++i,w=!w)for(char c:s.toCharArray())p+=e(w,c);for(;j<r;)p+=e(w,s.charAt(j++));return p;}int d(String s,String t){int l=s.length(),n=0,i=0;for(;i<l;)if(s.charAt(i)!=t.charAt(i++))++n;return n;}int h(String s,String t){int l=s.length(),m=t.length();return l>m?d(s,p(t,l)):l<m?d(p(s,m),t):d(s,t);}int h(String[]s){int l=s.length,i=0,j;int[]n=new int[l*l];for(;i<l;++i)for(j=i;++j<l;)n[i*l+j]=h(s[i],s[j]);return java.util.Arrays.stream(n).max().getAsInt();}

¡Puedes probarlo en línea !

Ungolfed y comentó:

// Encode the character (swap case)
char e(boolean w, char c) {
    return (char) (w & (64 < c & c < 91 | 96 < c & c < 123) ? c ^ 32 : c);
}

// Pad the string to desired length
String p(String s, int l) {
    var p = "";
    int m = s.length(), n = l / m, r = l % m, i = 0, j = 0;
    var w = 1 < 0;
    for (; i < n; ++i, w = !w)
        for (char c : s.toCharArray())
            p += e(w, c);
    for (; j < r;)
        p += e(w, s.charAt(j++));
    return p;
}

// Calculate the actual hamming distance between two same-length strings
int d(String s, String t) {
    int l = s.length(), n = 0, i = 0;
    for (; i < l;)
        if (s.charAt(i) != t.charAt(i++))
            ++n;
    return n;
}
// Pad the strings as needed and return their hamming distance
int h(String s, String t) {
    int l = s.length(), m = t.length();
    return l > m ? d(s, p(t, l)) : l < m ? d(p(s, m), t) : d(s, t);
}

    // Dispatch the strings and gather their hamming distances, return the max
int h(String[] s) {
    int l = s.length, i = 0, j;
    int[] n = new int[l * l];
    for (; i < l; ++i)
        for (j = i; ++j < l;)
            n[i * l + j] = h(s[i], s[j]);
    return java.util.Arrays.stream(n).max().getAsInt();
}

Yo sé que se puede lograr una mejor solución, especialmente para la parte de la cadena de sincronización.

EDITAR : afeite 8 bytes cambiando el tamaño de la matriz int hammingDistance()al cuadrado del número de cadenas dado. También repara un ArrayIndexOutOfBoundslanzamiento en uno de los casos de prueba.

EDIT 2 : guardado 33 bytes gracias a los comentarios de Kevin Cruijssen : declaración de clase eliminada, nombres acortados a 1 carácter, operadores cambiados, etc.

EDITAR 3 : Ahorre 1 byte y alcance el puntaje aprobado por Satanás cambiando el método con var-arg a array.

EDIT 4 : Ahorre otros 50 bytes gracias a Kevin Cruijssen , nuevamente: actualice la versión de Java de 8 a 10 para usar la varpalabra clave, la StringBuilderinstancia eliminada , etc.

joH1
fuente
1
No tengo mucho tiempo, pero algunas cosas básicas para jugar al golf: abandonar la clase, solo los métodos son suficientes. Cambie todos los nombres de métodos y variables a bytes individuales. Entonces, en lugar de hammingDistanceusar do alguna otra variable no utilizada. La mayor parte de tu &&puede ser &y ||puede ser |. c^' 'puede ser c^32. boolean w = false;puede ser boolean w=0>1;. i=0en el bucle se puede eliminar la inicialización y cambiar ,i,ja ,i=0,j. ++jpuede eliminarse y ++agregarse a .charAt(j++). .toString()puede ser +"". for(j=i+1;j<l;++j)puede ser for(j=0;++j<l;). Etc. etc.
Kevin Cruijssen
1
Los consejos para jugar golf en Java y los consejos para jugar golf en <todos los idiomas> también pueden ser interesantes de leer. :)
Kevin Cruijssen
¡Gracias! Eso es un buen levantamiento de bytes. Gracias por los enlaces también, lo estoy revisando y editaré lo antes posible.
joH1
1
Votaron por el puntaje aprobado por Satanás. xD Algunas cosas más pequeñas: StringBuilderpuede ser StringBuffer(si cambia a Java 10 podría ser var b=new StringBuffer(l);. El booleany charpuede ser también var. Si no tiene Java 10 localmente, está disponible en TIO ). Además, for(;i<n;++i){for(char c:s.toCharArray())b.append(e(w,c));w=!w;}puede ser for(;i++<n;w=!w)for(char c:s.toCharArray())b.append(e(w,c));. Y estoy bastante seguro de que puede eliminarlo por StringBuffercompleto y simplemente usarlo Stringy en +=lugar de hacerlo append.
Kevin Cruijssen
Hombre, algunos meses de código limpio y buenas prácticas de codificación me hicieron olvidar cómo jugar al golf. Actualizaré mi respuesta e incluiré TIO.
joH1
1

05AB1E , 33 29 bytes

Ćü)€é©εćDš«s`g∍}®€¤‚ø€ζ€€Ë_Oà

Pruébelo en línea o verifique todos los casos de prueba .

Lo más probable es que se reduzca a la mitad en conteo de bytes, pero funciona.

Explicación:

Ć           # Enclose the input-list (adding the first item to the end of the list)
            #  i.e. ['ABC1','abcD','abCd32e'] → ['ABC1','abcD','abCd32e','ABC1']
 ü)         # Pair-vectorize each of them
            #  i.e. ['ABC1','abcD','abCd32e','ABC1']
            #   → [['ABC1','abcD'],['abcD','abCd32e'],['abCd32e','ABC1']]
   ێ       # Sort each pair by length
            #  i.e. [['ABC1','abcD'],['abcD','abCd32e'],['abCd32e','ABC1']]
            #   → [['ABC1','abcD'],['abcD','abCd32e'],['ABC1','abCd32e']]
     ©      # Store this list in the register to re-use later on
ε        }  # Map each inner list in this list to:
 ć          # Head extracted
            #  i.e. ['abcD','abCd32e'] → 'abcD' and ['abCd32e']
  Dš        # Duplicate it, and swap the capitalization of the copy
            #  i.e. 'abcD' → 'ABCd'
    «       # Then merge it together
            #  i.e. 'abcD' and 'ABCd' → 'abcDABCd'
     s`     # Swap so the tail-list is at the top of the stack, and get it's single item
            #  i.e. ['abCd32e'] → 'abCd32e'
       g    # Get the length of that
            #  i.e. 'abCd32e' → 7
           # Extend/shorten the string to that length
            #  i.e. 'abcDABCd' and 7 → 'abcDABC'
®           # Get the saved list from the register again
 €¤         # Get the tail from each
            #  i.e. [['ABC1','abcD'],['abcD','abCd32e'],['abCd32e','ABC1']]
            #   → ['abcD','abCd32e','abCd32e']
           # Pair it with the other list
            #  i.e. ['ABC1','abcDABC','ABC1abc'] and ['abcD','abCd32e','abCd32e']
            #   → [['ABC1','abcDABC','ABC1abc'],['abcD','abCd32e','abCd32e']]
    ø       # Zip it, swapping rows / columns
            #  i.e. [['ABC1','abcDABC','ABC1abc'],['abcD','abCd32e','abCd32e']]
            #   → [['ABC1','abcD'],['abcDABC','abCd32e'],['ABC1abc','abCd32e']]
     €ζ     # And then zip each pair again
            #  i.e. [['ABC1','abcD'],['abcDABC','abCd32e'],['ABC1abc','abCd32e']]
            #   → [['Aa','Bb','Cc','1D'],['aa','bb','cC','Dd','A3','B2','Ce'],['Aa','Bb','CC','1d','a3','b2','ce']]
           # Then for each inner list
           #  And for each inner string
  Ë         #   Check if all characters are the same
            #    i.e. 'aa' → 1
            #    i.e. 'cC' → 0
   _        # And inverse the booleans
            #  i.e. [['Aa','Bb','Cc','1D'],['aa','bb','cC','Dd','A3','B2','Ce'],['Aa','Bb','CC','1d','a3','b2','ce']]
            #   → [[1,1,1,1],[0,0,1,1,1,1,1],[1,1,0,1,1,1,1]]
O           # Then sum each inner list
            #  i.e. [[1,1,1,1],[0,0,1,1,1,1,1],[1,1,0,1,1,1,1]] → [4,5,6]
 à          # And take the max as result
            #  i.e. [4,5,6] → 6
Kevin Cruijssen
fuente
1

Java 11, 387 bytes

a->{int l=a.length,i=l,t,j=0,C[]=new int[l];var p=new String[l][2];for(;i-->0;p[i][0]=a[t>0?i:j],p[i][1]=a[t>0?j:i])t=a[i].length()<a[j=-~i%l].length()?1:0;i=0;for(var P:p){var s="";for(var x:P[0].getBytes())s+=(char)(x>64&x<91|x>96&x<123?x^32:x);for(P[0]=repeat(P[0]+s,t=P[1].length()).substring(0,t);t-->0;)if(P[0].charAt(t)!=P[1].charAt(t))C[i]++;i++;}for(int c:C)j=c>j?c:j;return j;}

Pruébalo en línea. (NOTA: dado que Java 11 aún no está en TIO, String.repeat(int)se ha emulado como repeat(String,int)para el mismo conteo de bytes).

Explicación:

a->{                      // Method with String-array parameter and integer return-type
  int l=a.length,         //  Length of the input-array
      i=l,                //  Index-integer, starting at the length
      t,j=0,              //  Temp-integers
      C[]=new int[l];     //  Count-array the same size as the input
  var p=new String[l][2]; //  String-pairs array the same size as the input
  for(;i-->0              //  Loop `i` in the range [`l`, 0)
      ;                   //    After every iteration:
       p[i][0]=           //     Set the first String of the pair at index `i` to:
               a[t>0?i:j],//      The smallest of the `i`'th or `j`'th Strings of the input-array
       p[i][1]=           //     And set the second String of the pair at index `i` to:
               a[t>0?j:i])//      The largest of the `i`'th or `j`'th Strings of the input-array
    t=a[i].length()<      //    If the length of the `i`'th item is smaller than
      a[j=-~i%l].length()?//    the length of the `i+1`'th item
                          //    (and set `j` to this `i+1` with wrap-around to 0 for the last item
       1                  //     Set `t` to 1 as flag
      :                   //    Else:
       0;                 //     Set `t` to 0 as flag
                          //  We've now created the String pairs, where each pair is sorted by length
  i=0;                    //  Reset `i` to 0
  for(var P:p){           //  Loop over the pairs
    var s="";             //   Temp-String starting empty
    for(var x:P[0].getBytes())
                          //   Loop over the characters of the first String of the pair
      s+=                 //    Append the temp-String with:
         (char)(x>64&x<91|x>96&x<123?
                         //      If the current character is a letter:
           x^32          //       Swap it's case before appending it to `s`
         :               //      Else (not a letter):
          x);            //       Append it to `s` as is
    for(P[0]=            //    Now replace the first String with:
        repeat(P[0]+s,   //     The first String appended with the case-swapped first String
               t=P[1].length())
                         //     Repeated `t` amount of times,
                         //     where `t` is the length of the second String of the pair
        .substring(0,t); //     And then shorten it to length `t`
        t-->0;)          //    Inner loop over the character of the now same-length Pairs
      if(P[0].charAt(t)!=P[1].charAt(t))
                         //     If the characters at the same indices in the pair are not equal
        C[i]++;          //      Increase the counter for this pair by 1
    i++;}                //    After every iteration of the outer loop,
                         //    increase `i` by 1 for the next iteration
  for(int c:C)           //  Now loop over the calculated counts
    j=c>j?c:j;           //   And set `j` to the maximum
  return j;}             //  And finally return this maximum `j` as result
Kevin Cruijssen
fuente
1

R , 173 bytes

function(x,U=utf8ToInt,N=nchar)max(combn(x,2,function(z,v=z[order(N(z))])sum(U(substr(Reduce(paste0,rep(c(v[1],chartr('A-Za-z','a-zA-Z',v[1])),n<-N(v[2]))),1,n))!=U(v[2]))))

Pruébalo en línea!

@ngm: Hice mi mejor esfuerzo para jugar golf con su código (con mis personalizaciones pesadas, por supuesto) pero, como bien sabe, R no es muy golfista manipulando cadenas: P

digEmAll
fuente
Apuesto a que esto puede ser inferior a 150 bytes, pero aún no estoy seguro de cómo.
Giuseppe
@Giuseppe: Sospecho que también ... pero no soy muy bueno escribiendo códigos de manipulación de cadenas cortas y R tampoco me ayuda mucho: D
digEmAll
@digEmAll No voy a tratar de resolver mi propio desafío, pero pocas posibilidades pueden incluir outerobtener todas las combinaciones y hacer aritmética modular en los puntos de código en lugar de chartr.
ngm
@ngm: posible ... descarté el enfoque aritmético porque no pude encontrar una solución / fórmula corta para cambiar el caso de las letras sin tocar los números ...
digEmAll