Distância máxima de Hamming entre uma lista de cordas acolchoadas

18

A distância de Hamming entre duas strings de igual comprimento é o número de posições nas quais os caracteres correspondentes são diferentes. Se as cordas não tiverem o mesmo comprimento, a distância de Hamming não será definida.

Desafio

Escreva um programa ou função que encontre a maior distância de Hamming dentre todos os pares de cadeias de uma lista de cadeias, preenchida conforme necessário, de acordo com as regras descritas abaixo.

Os personagens serão de dentro a-zA-Z0-9.

As cadeias podem não ter o mesmo comprimento; portanto, para cada comparação, a cadeia mais curta deve ser preenchida da seguinte maneira:

  • enrole a corda desde o início quantas vezes for necessário para corresponder ao comprimento necessário
  • mude os casos das letras cada vez que invólucro estranho (1º, 3º, 5º, etc.)
  • deixe as coisas do lado de fora a-zA-Zinalteradas ao embrulhar

Por exemplo, digamos que você precise preencher a sequência de 5 caracteres ab9Cdpara que ela termine com 18 caracteres. Você terminaria com:

ab9CdAB9cDab9CdAB9
     ^^^^^     ^^^

com ^adicionado debaixo das 1ª e 3ª envoltórios de destaque às mudanças de caso.

Entrada / Saída

O formato de entrada / saída é flexível. Você pode assumir que a entrada possui pelo menos duas strings e que todas as strings terão pelo menos um caractere.

A saída é um número inteiro.

Regras

Isso é . Aplicam-se regras padrão.

Casos de teste

[ "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

Implementação de referência

Testei os exemplos com o código R (completamente não destruído) que você pode tentar aqui para comparar outros exemplos que você pode experimentar com o seu código.

ngm
fonte
1
alterar os casos das letras de cada vez embrulho estranho - Oh menino, esta exigência vai ser uma dor para minha solução ... Eu gosto do desafio, embora, por isso +1
Mr. Xcoder
Caso de teste sugerido: ["AacaAc", "Aab"] => 2. Um golfe intencional para a minha resposta Jelly teria falhado nesse caso, mas passaria por todos os outros.
Mr. Xcoder
@ngm Excelente desafio! +1
Don Thousand

Respostas:

7

Gelatina , 20 bytes

Não estou realmente feliz com isso. Deve ser jogável, mesmo com ~ 15 bytes, talvez.

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

Experimente online!

ou Confira uma suíte de testes!

Explicação

LÞŒcµṁ / sḢL $ ŒsÐeFn) §Ṁ Programa completo ou link monádico. N = entrada. | Exemplo: ["abc12D5", "abC34d3", "ABC14dabc23DAbC89d"]
L Classifique N pelo comprimento. | [['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 ']] (em Jelly, as strings são uma lista de caracteres)
  Pairsc Pares não ordenados: [x, y] para todos os x distintos, y em N. | [[['a', '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',
                        Aqui, por distinto, quero dizer em posições diferentes. |
    µ) Mapa com um link monádico. |
     Mold / Molde x como y. Ou seja, ciclo x até atingir o comprimento y. | [['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 $ Divida em pedaços de comprimento de x. | [[['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 ']]]
           Troque o caso de pedaços indexados pares (indexados 1). | [[['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 Achate. | [['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 Desigualdade vetorizada com y. | [[[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]], [[1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1]]]]]
                  § Depois de finalizar o mapa, some cada array bool (0 ou 1). | [[5], [17], [14]]
                   Ṁ Máximo. | 17
Mr. Xcoder
fonte
Não conheço totalmente Jelly, mas acho que você pode omitir e ainda obter o mesmo máximo no final.
quer
@ChasBrown Ugh, não, eu deveria precisa disso. Caso contrário, em vez de preencher o mais curto com o comprimento do mais longo, ṁ/em vez disso, apararia o maior com o comprimento do menor em alguns casos, o que não é o que queremos ... Acho que os casos de teste são muito bem escolhidos (e isso é um pouco infeliz coincidência) ...
Mr. Xcoder
@ChasBrown Como exemplo, tente ["AacaAc", "Aab"].
Mr. Xcoder
Ah sim, eu vejo ... Eu preciso me aprender mais alguma 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)

Experimente online!

Dadas duas cordas, s,t, zip((s+s.swapcase())*len(t),t))será uma lista de tuplas de comprimento len(t)desdezip trunca a menor iterable. Se len(s)<len(t), então, isso " socorre " com a troca de maiúsculas e minúsculas desejada e calculamos os sumcaracteres diferentes.

Se len(t)<=len(s), então o resultado sumserá menor ou igual ao sumse estávamos avaliando t,s; portanto, não tem efeito sobre o resultado maxnesse caso.

Chas Brown
fonte
Você pode usar em y!=vez de !=ysalvar 1
byt
@Senhor. Xcoder: Thx, mas acabei refazendo drasticamente a minha solução ...
Chas Brown
3

Geléia , 19 bytes

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

Experimente online!

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
fonte
2

Ruby , 89 82 bytes

Cria o produto cruzado da lista de entrada contra si próprio antes de calcular a distância de Hamming de cada par, usando um método de duplicação semelhante à resposta de Chas Brown . Porém, o Ruby não pode compactar as seqüências de caracteres ou adicionar booleanos sem sobrecarga adicional; portanto, torna-se necessário percorrer manualmente o par de cadeias de caracteres.

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

Experimente online!

Value Ink
fonte
1
82 bytes
GB
2

Java 10 ,748 740 667 666 616 bytes

Este deve ser o mais denso e ilegível, mas o golfe mais longo que já vi.

Chame o método h(String[])com uma matriz explícita (sem var argumentos): por exemplo,

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

retorna 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();}

Você pode experimentá-lo online !

Ungolfed e comentou:

// 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();
}

Eu sei que uma solução melhor pode ser alcançada, especialmente para a parte de emparelhamento de cordas.

EDIT : reduza 8 bytes alterando o tamanho da matriz int hammingDistance()para o quadrado do número de strings fornecidas. Ele também corrige umArrayIndexOutOfBounds lançamento em um dos casos de teste.

EDIT 2 : Salvo 33 bytes graças aos comentários de Kevin Cruijssen : declaração de classe removida, nomes encurtados para 1 caractere, operadores alterados etc.

EDIT 3 : Economize 1 byte e alcance a pontuação aprovada por Satanás, alterando o método com var-arg para array.

EDIT 4 : Salve outros 50 bytes graças a Kevin Cruijssen , novamente: atualize a versão Java de 8 para 10 para usar varpalavras-chave, StringBuilderinstância removida etc.

joH1
fonte
1
Não tenho muito tempo, mas algumas coisas básicas para o golfe: Abandone a classe, apenas os métodos são suficientes. Altere todos os nomes de métodos e variáveis ​​para bytes únicos. Portanto, em vez de hammingDistanceusar dou alguma outra variável não utilizada. A maior parte do seu &&pode ser &e ||pode ser |. c^' 'pode ser c^32. boolean w = false;pode ser boolean w=0>1;. i=0a inicialização do loop pode ser removida e altere ,i,jpara ,i=0,j. ++jpode ser removido e ++adicionado ao .charAt(j++). .toString()pode ser+"" . for(j=i+1;j<l;++j)pode ser for(j=0;++j<l;). Etc. etc.
Kevin Cruijssen
1
Dicas para jogar golfe em Java e Dicas para jogar em <todos os idiomas> também podem ser interessantes para ler. :)
Kevin Cruijssen
Obrigado! Isso é um bom levantamento de bytes. Obrigado pelos links também, estou dando uma olhada nele e editarei o mais rápido possível!
precisa saber é
1
Voto positivo para a pontuação aprovada por Satanás. xD Mais algumas pequenas coisas: StringBuilderpode ser StringBuffer(se você alternar para o Java 10, pode ser var b=new StringBuffer(l);. O booleane chartambém pode ser var. Se você não possui o Java 10 localmente, ele está disponível no TIO ). Além disso, for(;i<n;++i){for(char c:s.toCharArray())b.append(e(w,c));w=!w;}pode ser for(;i++<n;w=!w)for(char c:s.toCharArray())b.append(e(w,c));. E eu tenho certeza que você pode remover StringBuffercompletamente e apenas usar Stringe +=não append.
Kevin Cruijssen
Cara, alguns meses de código limpo e boas práticas de codificação me fizeram esquecer como jogar golfe! Vou atualizar minha resposta e incluir o TIO.
JoH1 16/08/19
1

05AB1E , 33 29 bytes

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

Experimente online ou verifique todos os casos de teste .

Provavelmente pode ser dividido pela metade na contagem de bytes, mas funciona ..

Explicação:

Ć           # 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
fonte
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;}

Experimente online. (NOTA: Como o Java 11 ainda não está no TIO, String.repeat(int)ele foi emulado como repeat(String,int)para a mesma contagem de bytes.)

Explicação:

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
fonte
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]))))

Experimente online!

@ngm: Eu tentei o meu melhor no golfe do seu código (com minhas personalizações pesadas, é claro), mas, como você bem sabe, R não gosta muito de manipular strings: P

digEmAll
fonte
Aposto que isso pode ter menos de 150 bytes, mas ainda não tenho certeza.
Giuseppe
@Giuseppe: Eu suspeito que também ... mas eu não sou realmente bom em escrever seqüências curtas códigos de manipulação e R não me ajuda muito também: D
digEmAll
@digEmAll Não vou tentar resolver meu próprio desafio, mas poucas possibilidades podem incluir outerobter todas as combinações e fazer aritmética modular nos pontos de código em vez de chartr.
Ng
@ngm: possível ... Eu descartou a abordagem aritmética, porque eu não poderia encontrar uma pequena solução / fórmula para alterar o caso para letras sem tocar os números ...
digEmAll