Código de Subseqüência Comum Mais Longo e Mais Curto


11

Sua tarefa de resolver o problema do SLCSC, que consiste em encontrar o menor código possível para resolver o problema de Maior Subseqüência Comum Mais Longa .

A solução válida para o problema LCS para duas ou mais cadeias S 1 , ... S n é qualquer string T de comprimento máximo de tal forma que os personagens de T aparecer em todos S i , na mesma ordem como em T .

Note-se que T não tem que ser uma sub seqüência de S i .

Exemplo

As cadeias axbycze xaybzctêm 8 subsequências comuns de comprimento 3:

abc abz ayc ayz xbc xbz xyc xyz

Qualquer uma dessas seria uma solução válida para o problema do LCS.

Detalhes

Escreva um programa ou uma função que resolva o problema do LCS, conforme explicado acima, cumprindo as seguintes regras:

  • A entrada consistirá em duas ou mais cadeias contendo apenas letras minúsculas.

    Você pode ler essas strings como uma matriz de strings ou uma única string com um delimitador de sua escolha.

  • Seu código deve gerar qualquer uma das soluções possíveis para o problema, opcionalmente seguida por um avanço de linha ou entre aspas.

  • Você pode supor que as seqüências de caracteres tenham menos de 1.000 caracteres e que no máximo 20 sejam.

    Dentro desses limites, seu código deve funcionar como esperado na teoria (com tempo e memória ilimitados).

  • Seu código deve concluir os casos de teste combinados da próxima seção em menos de uma hora na minha máquina (Intel Core i7-3770, 16 GiB RAM).

    As abordagens que simplesmente iteram sobre todas as subsequências possíveis não estarão em conformidade com o prazo.

  • O uso de built-ins que trivializam essa tarefa, como LongestCommonSequence, não é permitido.

Aplicam-se as regras de padrão .

Casos de teste

a
ab

Resultado: a


aaaaxbbbb
bbbbxcccc
ccccxaaaa

Resultado: x


hxbecqibzpyqhosszypghkdddykjfjcajnwfmtfhqcpavqrtoipocijrmqpgzoufkjkyurczxuhkcpehbhpsuieqgjcepuhbpronmlrcgvipvibhuyqndbjbrrzpqbdegmqgjliclcgahxoouqxqpujsyfwbdthteidvigudsuoznykkzskspjufgkhaxorbrdvgodlb
qnnprxqpnafnhekcxljyysobbpyhynvolgtrntqtjpxpchqwgtkpxxvmwwcohxplsailheuzhkbtayvmxnttycdkbdvryjkfhshulptkuarqwuidrnjsydftsyhuueebnrjvkfvhqmyrclehcwethsqzcyfvyohzskvgttggndmdvdgollryqoswviqurrqhiqrqtyrl

Saída: hxbbpyhogntqppcqgkxchpsieuhbncvpuqndbjqmclchqyfttdvgoysuhrrlou qualquer outra subsequência comum do mesmo comprimento


riikscwpvsbxrvkpymvbbpmwclizxlhihiubycxmxwviuajdzoonjpkgiuiulbjdpkztsqznhbjhymwzkutmkkkhirryabricvhb
jnrzutfnbqhbaueicsvltalvqoorafnadevojjcsnlftoskhntashydksoheydbeuwlswdzivxnvcrxbgxmquvdnfairsppodznm
kzimnldhqklxyezcuyjaiasaeslicegmnwfavllanoolkhvqkjdvxrsjapqqwnrplcwqginwinktxnkfcuuvoyntrqwwucarfvjg

Saída: icsvllvjnlktywuarou qualquer outra subsequência comum do mesmo comprimento


rblartqkfggrjpiipuzzypkycnyckkcqceeujiyy
yfpnedyjtiwrhyuktripdwyvgkblzodeufkelhub
ywcyboxwqkibwvredkrbdsyudkulpvmhixeqxynh
bnxwahbzhwjxkotnvbxrojkkldtsodtjmvdrmbgr

Saída: krkkou qualquer outra subsequência comum do mesmo comprimento


bwfscmotshoczmduwaev
coywaaizdaxjovipsmeh
dobzcpoiedenzlfdjpiu
bbhfeqscvvbwkuoxdoge
drqrzwbcpcsvneodelja

Saída: codeou qualquer outra subsequência comum do mesmo comprimento


nqrualgoedlf
jgqorzglfnpa
fgttvnogldfx
pgostsulyfug
sgnhoyjlnfvr
wdttgkolfkbt

Saída: golfou qualquer outra subsequência comum do mesmo comprimento


epopyfuhgowedpiqpgfj
ddxyestqynpwmytxhozm
ptubgzyqqksieoovuezv
tovotqmnhgzttfpywjgr
aomvytkgaijlgqzkljls
vzvxpaixrnprxvenbbuo
syfuwxlpcyontqlmfvib
arxleuomstkjegpduwcx
xgqrxaopouvkvwgbzewn
yggunddigctgpnuztzai
izroomywwztdymqszsuo
kiawjnxjncdtufhkrjsp

Saída: a sequência vazia



@NotthatCharles Nem todos. Essa pergunta fornece apenas duas strings como entrada e não tem limite de tempo. Todas as respostas existentes usam abordagens ingênuas que são magnitudes muito lentas para cumprir as regras dessa pergunta.
Dennis

O último exemplo provavelmente leva mais tempo para calcular, no entanto, removendo primeiro todos os caracteres que não aparecem em todas as strings, é trivial gerar a string vazia. Você poderia adicionar outro exemplo com o mesmo número de cadeias e comprimento de cadeias, onde todos os caracteres usados ​​aparecem em todas as cadeias e onde o LCS possui pelo menos cinco caracteres? Algo como: ghostbin.com/paste/x9caq
Tyilo

@Tylio A incorporação de alguma lógica que encerre a recursão mais cedo, se as strings não tiverem mais caracteres comuns, é basicamente o motivo do último caso de teste.
Dennis

@ Dennis Portanto, a solução não deve ser executada em tempo razoável, com 20 cordas arbitrárias de 1000 comprimentos?
Tyilo

Respostas:


4

CJam, 31

q~L{_:&\f{_2$f#:).>j+}{,}$W>s}j

Experimente online

9 bytes jogados graças a Dennis!

Explicação:

Esse algoritmo tenta todos os caracteres possíveis para a primeira posição da subsequência, substitui cada sequência pela substring após a primeira ocorrência desse caractere e, em seguida, chama-se recursivamente (com memorização).

q~          read and evaluate the input (taken as an array)
L{…}j       execute block with recursive memoization and no starting values
  _         duplicate the array of strings
  :&\       intersect the strings as character sets and move before the array
             these are all the possible characters for the sequence
  f{…}      for each character and the array
    _2$     duplicate the array and the character
    f#      find the character position in each string
    :)      increment the positions (to skip the character)
    .>      slice each string starting at the corresponding position
    j       call the j block recursively
    +       concatenate the starting character with the result
  {,}$      sort resulting strings (one for each character) by length
  W>        keep only the last element, if any
  s         convert (from 0/1-string array) to string

5

Python - 665 644

Níveis de indentação:

1: space
2: tab
3: tab + space
4: 2 tabs
5: 2 tabs + space

O código define uma função o, que pega uma lista de cadeias como argumentos e retorna um dos LCSs para as cadeias.

def o(t):
 t=[[y for y in x if y in reduce(lambda x,y:x.intersection(y),t,set(t[0]))]for x in t];l=map(len,t);C=[0]*reduce(lambda x,y:x*-~y,l,1);y=lambda z:[x-1for x in z];m=len(t);e=enumerate
 def g(h):
    r,x=0,1
    for k,j in e(h):r+=-~j*x;x*=-~l[k]
    return r
 def f(h):
    i=len(h)
    if i==m:
     b=g(h);c=t[0][h[0]]
     for k,j in e(h):
         if t[k][j]!=c:break
     else:C[b]=1+C[g(y(h))];return
     r=0
     for k,_ in e(h):a=h[:];a[k]-=1;r=max(r,C[g(a)])
     C[b]=r;return
    for j,_ in e(t[i]):f(h+[j])
 def p(h):
    if min(h)==-1:return''
    v=C[g(h)]
    for k,_ in e(h):
        a=h[:];a[k]-=1
        if v==C[g(a)]:return p(a)
    return p(y(h))+t[0][h[0]]
 f([]);return p(y(l))

Código do teste:

tests = [
"""
a
ab
""",
"""
aaaaxbbbb
bbbbxcccc
ccccxaaaa
""",
"""
hxbecqibzpyqhosszypghkdddykjfjcajnwfmtfhqcpavqrtoipocijrmqpgzoufkjkyurczxuhkcpehbhpsuieqgjcepuhbpronmlrcgvipvibhuyqndbjbrrzpqbdegmqgjliclcgahxoouqxqpujsyfwbdthteidvigudsuoznykkzskspjufgkhaxorbrdvgodlb
qnnprxqpnafnhekcxljyysobbpyhynvolgtrntqtjpxpchqwgtkpxxvmwwcohxplsailheuzhkbtayvmxnttycdkbdvryjkfhshulptkuarqwuidrnjsydftsyhuueebnrjvkfvhqmyrclehcwethsqzcyfvyohzskvgttggndmdvdgollryqoswviqurrqhiqrqtyrl
""",
"""
riikscwpvsbxrvkpymvbbpmwclizxlhihiubycxmxwviuajdzoonjpkgiuiulbjdpkztsqznhbjhymwzkutmkkkhirryabricvhb
jnrzutfnbqhbaueicsvltalvqoorafnadevojjcsnlftoskhntashydksoheydbeuwlswdzivxnvcrxbgxmquvdnfairsppodznm
kzimnldhqklxyezcuyjaiasaeslicegmnwfavllanoolkhvqkjdvxrsjapqqwnrplcwqginwinktxnkfcuuvoyntrqwwucarfvjg
""",
"""
rblartqkfggrjpiipuzzypkycnyckkcqceeujiyy
yfpnedyjtiwrhyuktripdwyvgkblzodeufkelhub
ywcyboxwqkibwvredkrbdsyudkulpvmhixeqxynh
bnxwahbzhwjxkotnvbxrojkkldtsodtjmvdrmbgr
""",
"""
bwfscmotshoczmduwaev
coywaaizdaxjovipsmeh
dobzcpoiedenzlfdjpiu
bbhfeqscvvbwkuoxdoge
drqrzwbcpcsvneodelja
""",
"""
nqrualgoedlf
jgqorzglfnpa
fgttvnogldfx
pgostsulyfug
sgnhoyjlnfvr
wdttgkolfkbt
""",
"""
epopyfuhgowedpiqpgfj
ddxyestqynpwmytxhozm
ptubgzyqqksieoovuezv
tovotqmnhgzttfpywjgr
aomvytkgaijlgqzkljls
vzvxpaixrnprxvenbbuo
syfuwxlpcyontqlmfvib
arxleuomstkjegpduwcx
xgqrxaopouvkvwgbzewn
yggunddigctgpnuztzai
izroomywwztdymqszsuo
kiawjnxjncdtufhkrjsp
"""
]

for s in tests:
 print o(s.strip().split())

Tempo necessário para executar os testes no meu computador:

$ time python 52808-shortest-longest-common-subsequence-code-golfed.py
a
x
hecbpyhogntqtpcqgkxchpsieuhbncvhuqndbjqmclchqyfhtdvgoysuhrrl
icsvllvanlktywuar
krkk
code
golf

        9.03 real         8.99 user         0.03 sys

1
Você deve adicionar um byte para obter seu código em 666 bytes. Tão metal. \ m /
Alex A.

@AlexA. Sim, também notei que, ao contar os bytes, ele incluía uma nova linha na última linha.
Tyilo

Existem algumas pequenas melhorias que vejo imediatamente que devem ajudar. Em primeiro lugar, em qualquer lugar que você tenha um (n+1), você pode substituí-lo por -~npara salvar 2 bytes em cada caso. Além disso, em qualquer lugar que você use mapcom a lambda, considere usar a compreensão da lista. Por exemplo, map(lambda x:x-1,z)pode ser reduzido por três bytes, alterando-o para [~-x for x in z].
Kade

r,x=r+(j+1)*x,x*(l[k]+1)pode ser reduzido para r+=(j+1)*x;x*=(l[k]+1). Além disso, você não precisa, u=...porque ué usado apenas em um lugar. Apenas substitua esse código pela letra u.
mbomb007

@ Vioz- e mbomb007 Obrigado.
Tyilo 11/07

4

Pitão, 59 58 55 35 bytes

L&@Fb?+yPMbeeb@FeMbeolNmyXJbdP@bdlb

Corte 20 bytes graças a @isaacg!

Versão de 55 bytes:

DCHR?k!&.AH@FH?+Cm<1dHeeHql{medH1h.MlZ.eC++<Hk]<1b>HhkH

Corte 3 bytes alterando .U@bZpara @F(o operador fold).

Versão de 58 bytes:

DCHR?k!&.AH.U@bZH?+Cm<1dHeeHql{medH1h.MlZ.eC++<Hk]<1b>HhkH

Corte um byte alterando o formato de uma condicional booleana.

Versão de 59 bytes:

DCHR?k|!.AH!.U@bZH?+Cm<1dHeeHql{medH1h.MlZ.eC++<Hk]<1b>HhkH

Isso foi difícil! O Python continuava em falha! Tenho certeza de que era algum tipo de bug, mas não consegui um caso de teste mínimo. Ah bem.

Baseei o algoritmo neste . O que é bom, exceto que aquele foi projetado para apenas duas seqüências de caracteres. Eu tive que ajustá-lo um pouco para fazer funcionar mais. Em seguida, o último caso de teste estava demorando muito, então tive que adicionar uma verificação adicional para sair da recursão se não houver caracteres mais comuns.

É bem lento, mas deve levar menos de uma hora (espero). Estou testando no meu Core i3 com 6 GB de RAM, portanto, o seu Core i7 de 16 GB deve passar por isso. :)

Eu também aproveitei as funções de memorização automática do Pyth para torná-lo um pouco mais rápido.

EDIT : @Dennis disse que passa!

Para testá-lo, adicione a seguinte linha:

CQ

e forneça uma lista de strings via entrada padrão (por exemplo ['a', 'ab']).

Explicação para a versão de 35 bytes:

WIP.

Explicação para a versão de 55 bytes:

DCH                                                        define a function C that takes a list of strings H
   R                                                       return the following expression
    ?                                                      if
      !&.AH@FH                                             there are no more common letters OR all the strings are empty
     k                                                     return the empty string
              ?          ql{medH1                          else if the last character of every string is equal
               +Cm<1dHeeH                                  return the result of adding the last character to recursion with every item without its last character
                                 h.MlZ.eC++<Hk]<1b>HhkH    otherwise, return the largest result of recursing len(H) times, each time with one element's last character cut off

@Dennis Ok; Eu vou trabalhar nisso.
Kirbyfan64sos

@Dennis Updated. Você pode tentar novamente agora.
Kirbyfan64sos

O último caso de teste termina instantaneamente agora.
Dennis

@Dennis YESSSSS !!
Kirbyfan64sos

@ kirbyfan64sos Sobre os segfaults: Faça o python segfaults quando a profundidade da recursão for muito alta, como na recursão infinita.
Isaacg

4

C, 618 564 bytes

d,M,N,A[9999][2];char*(R[9999][20]),b[1000];L(char**s,n){char*j[20],c,a=0;int x[n],y=n-1,z,i,t,m=0,w=1;for(;y;)x[y--]=999;for(;y<N;y++){for(i=0;i<n&&s[i]==R[y][i];i++);if(i/n){a=A[y][0];m=A[y][1];w=0;if(m+d<M||!a)goto J;else{c=a;goto K;}}}for(c=97;w&&c<'{';c++){K:t=1,y=1,z=1;for(i=0;i<n;j[i++]++){for(j[i]=s[i];*j[i]-c;j[i]++)t&=!!*j[i];y&=j[i]-s[i]>x[i]?z=0,1:0;}t&=!y;I:if(t){if(z)for(i=0;i<n;i++)x[i]=j[i]-s[i];d++,t+=L(j,n),d--,m=t>m?a=c,t:m;}}if(w){for(y=0;y<n;y++)R[N][y]=s[y];A[N][0]=a;A[N++][1]=m;}J:if(d+m>=M)M=d+m,b[d]=a;if(!d)N=0,M=0,puts(b);return m;}

E aqui está desvendado, por "legibilidade":

d,M,N,A[9999][2];
char*(R[9999][20]),b[1000];
L(char**s,n){
    char*j[20],c,a=0;
    int x[n],y=n-1,z,i,t,m=0,w=1;
    for(;y;)
        x[y--]=999;
    for(;y<N;y++){
        for(i=0;i<n&&s[i]==R[y][i];i++);
        if(i/n){
            a=A[y][0];
            m=A[y][1];
            w=0;
            if(m+d<M||!a)
                goto J;
            else{
                c=a;
                goto K;
            }
        }
    }
    for(c=97;w&&c<'{';c++){
        K:
        t=1,
        y=1,
        z=1;
        for(i=0;i<n;j[i++]++){
            for(j[i]=s[i];*j[i]-c;j[i]++)
                t&=!!*j[i];
            y&=j[i]-s[i]>x[i]?z=0,1:0;
        }
        t&=!y;
        I:
        if(t){
            if(z)
                for(i=0;i<n;i++)
                    x[i]=j[i]-s[i];
            d++,
            t+=L(j,n),
            d--,
            m=t>m?a=c,t:m;
        }
    }
    if(w){
        for(y=0;y<n;y++)R[N][y]=s[y];
        A[N][0]=a;
        A[N++][1]=m;
    }
    J:
    if(d+m>=M)
        M=d+m,b[d]=a;
    if(!d)
        N=0,M=0,puts(b);
    return m;
}

Senhoras e senhores, cometi um erro horrível. É usado para ser mais bonita ... e Goto-less ... Pelo menos agora ele é rápido .

Definimos uma função recursiva Lque recebe como entrada uma matriz sde matrizes de caracteres e o número nde strings. A função gera a string resultante para stdout e, aliás, retorna o tamanho em caracteres dessa string.

A abordagem

Embora o código seja complicado, a estratégia aqui não é muito complexa. Começamos com um algoritmo recursivo bastante ingênuo, que descreverei com pseudocódigo:

Function L (array of strings s, number of strings n), returns length:

Create array of strings j of size n;

For each character c in "a-z",
    For each integer i less than n,
         Set the i'th string of j to the i'th string of s, starting at the first appearance of c in s[i]. (e.g. j[i][0] == c)
         If c does not occur in the i'th string of s, continue on to the next c.
    end For

    new_length := L( j, n ) + 1; // (C) t = new_length
    if new_length > best_length
        best_character := c; // (C) a = best_character
        best_length := new_length; // (C) m = best_length
    end if
end For

// (C) d = current_depth_in_recursion_tree
if best_length + current_depth_in_recursion_tree >= best_found
     prepend best_character to output_string // (C) b = output_string
     // (C) M = best_found, which represents the longest common substring found at any given point in the execution.
     best_found = best_length + current_depth;
end if

if current_depth_in_recursion_tree == 0
    reset all variables, print output_string
end if 

return best_length

Agora, esse algoritmo por si só é bastante atroz (mas pode caber em torno de ~ 230 bytes, eu descobri). Não é assim que se obtém resultados rápidos. Esse algoritmo escala incrivelmente mal com o comprimento da string. Este algoritmo faz , no entanto, escala razoavelmente bem com maior número de cordas. O último caso de teste seria resolvido virtualmente instantaneamente, já que nenhuma sequência de caracteres spossui caracteres cem comum. Foram implementados dois truques principais que resultaram em um incrível aumento de velocidade:

  • A cada chamada para L, verifique se recebemos essa mesma entrada antes. Como, na prática, as informações são passadas através de ponteiros para o mesmo conjunto de strings, na verdade não precisamos comparar strings, apenas locais, o que é ótimo. Se descobrimos que obtivemos essas informações antes, não há necessidade de executar os cálculos (na maioria das vezes, mas obter resultados torna isso um pouco mais complicado) e podemos nos safar apenas retornando o comprimento. Se não encontrarmos uma correspondência, salve esse conjunto de entrada / saída para comparar com chamadas futuras. No código C, o segundo forloop tenta encontrar correspondências para a entrada. Os ponteiros de entrada conhecidos são salvos Re os valores correspondentes de comprimento e saída de caracteres são armazenados emA. Esse plano teve um efeito drástico no tempo de execução, especialmente com seqüências mais longas.

  • Toda vez que encontramos os locais cem s, há uma chance de sabermos logo de cara que o que descobrimos não é o ideal. Se todos os locais caparecerem após algum local conhecido de outra letra, sabemos automaticamente que isso cnão leva a uma substring ideal, porque você pode colocar mais uma letra nela. Isso significa que, por um pequeno custo, podemos remover várias centenas de chamadas Lpara cadeias grandes. No código C acima, yé um conjunto de sinalizadores se soubermos automaticamente que esse caractere leva a uma sequência subótima e zé um conjunto de sinalizadores se encontrarmos um caractere que tenha aparências exclusivamente anteriores a qualquer outro caractere conhecido. As primeiras aparências atuais de caracteres são armazenadas emx. A implementação atual dessa idéia é um pouco confusa, mas quase dobrou o desempenho em muitos casos.

Com essas duas idéias, o que não terminou em uma hora agora levou cerca de 0,015 segundos.

Provavelmente existem muito mais pequenos truques que podem acelerar o desempenho, mas nesse momento comecei a me preocupar com minha capacidade de jogar tudo. Ainda não estou contente com o golfe, então provavelmente voltarei a isso mais tarde!

Horários

Aqui estão alguns códigos de teste, que eu convido você a experimentar online :

#include "stdio.h"
#include "time.h"

#define SIZE_ARRAY(x) (sizeof(x) / sizeof(*x))

int main(int argc, char** argv) {
    /* Our test case */
    char* test7[] = {
        "nqrualgoedlf",
        "jgqorzglfnpa",
        "fgttvnogldfx",
        "pgostsulyfug",
        "sgnhoyjlnfvr",
        "wdttgkolfkbt"
    };

    printf("Test 7:\n\t");
    clock_t start = clock();

    /* The call to L */
    int size = L(test7, SIZE_ARRAY(test7));


    double dt = ((double)(clock() - start)) / CLOCKS_PER_SEC;
    printf("\tSize: %d\n", size);
    printf("\tElapsed time: %lf s\n", dt);

    return 0;
}

Executei os casos de teste do OP em um laptop equipado com um chip Intel Core i7 de 1,7 GHz, com uma configuração de otimização de -Ofast. A simulação relatou um pico de 712 KB necessário. Aqui está um exemplo de execução de cada caso de teste, com tempos:

Test 1:
    a
    Size: 1
    Elapsed time: 0.000020 s
Test 2:
    x
    Size: 1
    Elapsed time: 0.000017 s
Test 3:
    hecbpyhogntqppcqgkxchpsieuhbmcbhuqdjbrqmclchqyfhtdvdoysuhrrl
    Size: 60
    Elapsed time: 0.054547 s
Test 4:
    ihicvaoodsnktkrar
    Size: 17
    Elapsed time: 0.007459 s
Test 5:
    krkk
    Size: 4
    Elapsed time: 0.000051 s
Test 6:
    code
    Size: 4
    Elapsed time: 0.000045 s
Test 7:
    golf
    Size: 4
    Elapsed time: 0.000040 s
Test 8:

    Size: 0
    Elapsed time: 0.000029 s


Total time: 0.062293 s

No golfe, atingi o desempenho de maneira bastante significativa e, como as pessoas pareciam gostar da velocidade bruta (0,013624 s para concluir todos os casos de teste combinados) da minha solução anterior de 618 bytes, deixarei aqui como referência:

d,M,N,A[9999][2];char*(R[9999][20]),b[1000];L(char**s,n){char*j[20],c,a=0;int x[n],y,z,i,t,m=0,w=1;for(y=0;y<n;y++)x[y]=999;for(y=0;y<N;y++){for(i=0;i<n;i++)if(s[i]!=R[y][i])break;if(i==n){a=A[y][0];m=A[y][1];w=0;if(m+d<M||!a)goto J;else{c=a;goto K;}}}for(c=97;w&&c<'{';c++){K:t=1,y=1,z=1;for(i=0;i<n;j[i++]++){for(j[i]=s[i];*j[i]-c;j[i]++)if(!*j[i]){t=0;goto I;}if(j[i]-s[i]>x[i])z=0;if(j[i]-s[i]<x[i])y=0;}if(y){t=0;}I:if(t){if(z){for(i=0;i<n;i++){x[i]=j[i]-s[i];}}d++,t+=L(j,n),d--,m=t>m?(a=c),t:m;}}if(w){for(y=0;y<n;y++)R[N][y]=s[y];A[N][0]=a;A[N++][1]=m;}J:if(d+m>=M)M=d+m,b[d]=a;if(!d)N=0,M=0,puts(b);return m;}

O algoritmo em si é inalterado, mas o novo código baseia-se em divisões e em algumas operações bit a bit mais complicadas que acabam atrasando tudo.


Eu estava pensando em postar um desafio de código mais rápido sobre um tópico semelhante, mas parece que não preciso mais. 0.01s e 712KB são simplesmente surpreendentes.
Dennis

Isso é simplesmente incrível!
kirbyfan64sos

Olhando para a sua explicação, o que diabos é best_found? É mencionado apenas duas vezes, uma quando é usada na condicional e a outra quando é redefinida.
precisa saber é o seguinte

Olhando sobre a fonte C, parece que best_foundestá definido como best_length + current_depth. Você provavelmente deve mencionar isso na explicação!
Kirbyfan64sos

@ kirbyfan64sos best_foundé um número inteiro global que descreve o comprimento da substring comum mais longa encontrada em qualquer ponto da execução. Vou colocar isso na explicação!
BrainSteel

1

Python 2, 285

Código:

import re
def f(s,a,b):
  if b==[]:return s+f('',[],a)
  if a==[]:return s+max([f(b[0][i],[b[0][i+1:]],b[1:]) for i in range(len(b[0]))],key=len) if b[0]!='' else ''
  return max([f(s,a+[b[0][i.start()+1:]],b[1:]) for i in re.finditer(s[-1],b[0])],key=len) if ~b[0].find(s[-1]) else ''

Uso:

print f('',[],['axbycz','xaybzc'])

Explicação:

Esta é uma função recursiva. sé o personagem que estamos procurando. acontém uma lista de seqüências de caracteres fatiadas depois s. bcontém uma lista de strings intocadas ainda. fretorna a string comum mais longa.

A primeira condição verifica se terminamos de examinar todas as strings. Nesse caso, significa scaractere comum e retorna se procura por caracteres mais comuns.

A segunda condição verifica se não começamos a passar por nenhuma sequência, o que significa que nem sequer temos um caractere ( a==[]é equivalente a s==''). Nesse caso, verificamos cada caractere da primeira string b.

A última linha move a primeira sequência bpara a, localizando cada ocorrência sdessa sequência.

Na primeira chamada, sdeve haver uma sequência vazia. adeve estar em uma lista vazia e bdeve conter todas as cadeias.


2
Você deve usar argumentos padrão para que apenas as strings precisem ser fornecidas à função, como f(b,s='',a=[]).
feersum
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.