Codice di conseguenza comune più breve più lungo


11

Il tuo compito di risolvere il problema SLCSC, che consiste nel trovare il codice più breve possibile per risolvere il problema della susseguenza comune più lunga .

Una valida soluzione al problema LCS per due o più stringhe S 1 , S ... n è qualsiasi stringa T di lunghezza massima tale che i caratteri di T appaiono in tutta S i , nello stesso ordine in T .

Si noti che T non deve essere un sub stringa di S i .

Esempio

Le stringhe axbycze xaybzchanno 8 sottosequenze comuni di lunghezza 3:

abc abz ayc ayz xbc xbz xyc xyz

Ognuno di questi sarebbe una soluzione valida per il problema LCS.

Dettagli

Scrivi un programma o una funzione che risolva il problema LCS, come spiegato sopra, rispettando le seguenti regole:

  • L'input sarà composto da due o più stringhe contenenti solo lettere minuscole.

    Puoi leggere quelle stringhe come una matrice di stringhe o una singola stringa con un delimitatore di tua scelta.

  • Il codice deve generare una qualsiasi delle possibili soluzioni al problema, facoltativamente seguito da un avanzamento riga o racchiuso tra virgolette.

  • Puoi presumere che le stringhe siano più corte di 1000 caratteri e che ci siano al massimo 20 stringhe.

    Entro questi limiti, il codice dovrebbe funzionare come previsto in teoria (dati tempo e memoria illimitati).

  • Il codice deve completare i casi di test combinati della sezione successiva in meno di un'ora sulla mia macchina (Intel Core i7-3770, 16 GiB RAM).

    Gli approcci che ripetono semplicemente tutte le sottosequenze possibili non rispettano il limite di tempo.

  • LongestCommonSequenceNon è consentito l' utilizzo di incorporati che banalizzano questa attività, come ad esempio .

Si applicano le regole standard del .

Casi test

a
ab

Produzione: a


aaaaxbbbb
bbbbxcccc
ccccxaaaa

Produzione: x


hxbecqibzpyqhosszypghkdddykjfjcajnwfmtfhqcpavqrtoipocijrmqpgzoufkjkyurczxuhkcpehbhpsuieqgjcepuhbpronmlrcgvipvibhuyqndbjbrrzpqbdegmqgjliclcgahxoouqxqpujsyfwbdthteidvigudsuoznykkzskspjufgkhaxorbrdvgodlb
qnnprxqpnafnhekcxljyysobbpyhynvolgtrntqtjpxpchqwgtkpxxvmwwcohxplsailheuzhkbtayvmxnttycdkbdvryjkfhshulptkuarqwuidrnjsydftsyhuueebnrjvkfvhqmyrclehcwethsqzcyfvyohzskvgttggndmdvdgollryqoswviqurrqhiqrqtyrl

Output: hxbbpyhogntqppcqgkxchpsieuhbncvpuqndbjqmclchqyfttdvgoysuhrrlo qualsiasi altra sottosequenza comune della stessa lunghezza


riikscwpvsbxrvkpymvbbpmwclizxlhihiubycxmxwviuajdzoonjpkgiuiulbjdpkztsqznhbjhymwzkutmkkkhirryabricvhb
jnrzutfnbqhbaueicsvltalvqoorafnadevojjcsnlftoskhntashydksoheydbeuwlswdzivxnvcrxbgxmquvdnfairsppodznm
kzimnldhqklxyezcuyjaiasaeslicegmnwfavllanoolkhvqkjdvxrsjapqqwnrplcwqginwinktxnkfcuuvoyntrqwwucarfvjg

Output: icsvllvjnlktywuaro qualsiasi altra sottosequenza comune della stessa lunghezza


rblartqkfggrjpiipuzzypkycnyckkcqceeujiyy
yfpnedyjtiwrhyuktripdwyvgkblzodeufkelhub
ywcyboxwqkibwvredkrbdsyudkulpvmhixeqxynh
bnxwahbzhwjxkotnvbxrojkkldtsodtjmvdrmbgr

Output: krkko qualsiasi altra sottosequenza comune della stessa lunghezza


bwfscmotshoczmduwaev
coywaaizdaxjovipsmeh
dobzcpoiedenzlfdjpiu
bbhfeqscvvbwkuoxdoge
drqrzwbcpcsvneodelja

Output: codeo qualsiasi altra sottosequenza comune della stessa lunghezza


nqrualgoedlf
jgqorzglfnpa
fgttvnogldfx
pgostsulyfug
sgnhoyjlnfvr
wdttgkolfkbt

Output: golfo qualsiasi altra sottosequenza comune della stessa lunghezza


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

Output: la stringa vuota



@NotthatCharles Non tutti. Questa domanda fornisce solo due stringhe come input e non ha limiti di tempo. Tutte le risposte esistenti utilizzano approcci ingenui che sono troppo lenti per rispettare le regole di questa domanda.
Dennis,

L'ultimo esempio probabilmente richiede il tempo più lungo per il calcolo, tuttavia rimuovendo prima ogni carattere che non appare in ogni stringa è banale produrre la stringa vuota. Potresti aggiungere un altro esempio con lo stesso numero di stringhe e la lunghezza delle stringhe, in cui ogni carattere utilizzato appare in ogni stringa e dove LCS ha almeno 5 caratteri? Qualcosa del tipo: ghostbin.com/paste/x9caq
Tyilo

@Tylio Incorporare un po 'di logica che pone fine alla ricorsione in anticipo se le stringhe non hanno più caratteri comuni è praticamente ciò di cui tratta l'ultimo caso di test.
Dennis,

@Dennis Quindi la soluzione non dovrebbe essere in grado di funzionare in tempi ragionevoli con 20 stringhe di lunghezza arbitraria 1000?
Tyilo,

Risposte:


4

CJam, 31

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

Provalo online

9 byte giocati a golf grazie a Dennis!

Spiegazione:

Questo algoritmo prova ogni carattere possibile per la prima posizione della sottosequenza, sostituisce ogni stringa con la sottostringa dopo la prima occorrenza di quel carattere e quindi si chiama ricorsivamente (con memoization).

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

Livelli di rientro:

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

Il codice definisce una funzione o, che accetta un elenco di stringhe come argomenti e restituisce uno degli LCS per le stringhe.

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

Codice di prova:

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 impiegato per eseguire i test sul mio computer:

$ 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
È necessario aggiungere un byte per ottenere il codice a 666 byte. Quindi metallo. \ m /
Alex A.

@AlexA. Sì, ho anche notato che quando si contano i byte in quanto includeva una nuova riga nell'ultima riga.
Tyilo,

Ci sono alcuni piccoli miglioramenti che vedo subito che dovrebbero aiutare. In primo luogo, ovunque tu abbia un (n+1), puoi sostituirlo con -~nper salvare 2 byte in ogni caso. Inoltre, ovunque tu usi mapcon a lambda, considera invece l'uso della comprensione dell'elenco. Ad esempio, map(lambda x:x-1,z)può essere ridotto di tre byte modificandolo in[~-x for x in z] .
Kade,

r,x=r+(j+1)*x,x*(l[k]+1)può essere abbreviato in r+=(j+1)*x;x*=(l[k]+1). Inoltre, non è necessario u=...perché uviene utilizzato solo in un posto. Sostituisci semplicemente quel codice con la lettera u.
mbomb007,

@ Vioz- e mbomb007 Grazie.
Tyilo,

4

Pyth, 59 58 55 35 byte

L&@Fb?+yPMbeeb@FeMbeolNmyXJbdP@bdlb

Taglia di ben 20 byte grazie a @isaacg!

Versione a 55 byte:

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

Tagliare 3 byte cambiando .U@bZin @F(l'operatore di piegatura).

Versione a 58 byte:

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

Taglia un byte modificando il formato di un condizionale booleano.

Versione a 59 byte:

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

Questo è stato difficile! Python continuava a segfaultare! Abbastanza sicuro che fosse una specie di bug, ma non sono riuscito a ottenere un minimo test case. Oh bene.

Ho basato l'algoritmo su questo . Il che va bene, tranne che quello è progettato per solo due stringhe. Ho dovuto modificarlo un po 'per farlo funzionare di più. Quindi, l'ultimo caso di test stava impiegando troppo tempo, quindi ho dovuto aggiungere un ulteriore controllo per uscire dalla ricorsione se non ci sono più caratteri comuni.

È piuttosto lento, ma dovrebbe richiedere meno di un'ora (si spera). Sto testando il mio Core i3 con 6 GB di RAM, quindi il tuo Core i7 da 16 GB dovrebbe esplodere. :)

Ho anche sfruttato le funzioni di memorizzazione automatica di Pyth per renderlo un po 'più veloce.

EDIT : @Dennis ha detto che passa!

Per provarlo, aggiungi la seguente riga:

CQ

e dagli un elenco di stringhe tramite input standard (ad es ['a', 'ab'] .).

Spiegazione per la versione a 35 byte:

WIP.

Spiegazione per la versione a 55 byte:

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; Ci lavorerò sopra.
Kirbyfan64sos,

@Dennis Aggiornato. Puoi riprovare ora.
Kirbyfan64sos,

L'ultimo test case termina all'istante adesso.
Dennis,

@Dennis YESSSSS !!
Kirbyfan64sos,

@ kirbyfan64sos Informazioni sui segfaults: Pyth segfaults quando la profondità della ricorsione è troppo elevata, come ad esempio sulla ricorsione infinita.
isaacg,

4

C, 618 564 byte

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 qui è svelato, per "leggibilità":

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

Onorevoli colleghi, ho fatto un terribile errore. Un tempo era più bello ... E meno goto ... Almeno ora è veloce .

Definiamo una funzione ricorsiva Lche accetta come input una matrice sdi matrici di caratteri e il numeron di stringhe. La funzione restituisce la stringa risultante a stdout e, per inciso, restituisce la dimensione in caratteri di quella stringa.

L'approccio

Sebbene il codice sia contorto, la strategia qui non è troppo complessa. Iniziamo con un algoritmo ricorsivo piuttosto ingenuo, che descriverò con lo pseudocodice:

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

Ora, questo algoritmo da solo è piuttosto atroce (ma può essere inserito in circa ~ 230 byte, ho scoperto). Non è così che si ottengono risultati rapidi. Questo algoritmo si ridimensiona incredibilmente male con la lunghezza della stringa. Questo algoritmo ha , tuttavia, scala abbastanza bene con un numero maggiore di stringhe. L'ultimo caso di test verrebbe risolto praticamente all'istante, poiché nessuna stringa sha caratteri cin comune. Ci sono stati due trucchi principali che ho implementato sopra che hanno portato a un incredibile aumento della velocità:

  • Ad ogni chiamata a L, controlla se ci è stato dato lo stesso input prima. Dato che in pratica le informazioni vengono passate attraverso i puntatori allo stesso set di stringhe, in realtà non dobbiamo confrontare stringhe, ma solo posizioni, il che è fantastico. Se scopriamo di aver ottenuto queste informazioni prima, non è necessario eseguire i calcoli (la maggior parte delle volte, ma ottenere l'output rende questo un po 'più complicato) e possiamo farcela semplicemente restituendo la lunghezza. Se non troviamo una corrispondenza, salva questo set di input / output per confrontarlo con le chiamate future. Nel codice C, il secondofor ciclo tenta di trovare corrispondenze all'input. I puntatori di input noti vengono salvati e vengono memorizzati Ri corrispondenti valori di lunghezza e output dei caratteriA. Questo piano ha avuto un effetto drastico sul runtime, specialmente con stringhe più lunghe.

  • Ogni volta che troviamo le posizioni di cin s, c'è una possibilità che sappiamo subito che ciò che abbiamo trovato non è ottimale. Se ogni posizione di cappare dopo una posizione nota di un'altra lettera, sappiamo automaticamente che ciò cnon porta a una sottostringa ottimale, perché puoi inserire un'altra lettera in essa. Ciò significa che per un piccolo costo, possiamo potenzialmente rimuovere diverse centinaia di chiamate Lper stringhe di grandi dimensioni. Nel codice C sopra, yè impostato un flag se sappiamo automaticamente che questo carattere porta a una stringa non ottimale, ed zè un flag impostato se troviamo un carattere che ha apparenze esclusivamente precedenti rispetto a qualsiasi altro carattere noto. Le attuali prime apparizioni di personaggi sono memorizzate inx. L'attuale implementazione di questa idea è un po 'confusa, ma quasi raddoppia le prestazioni in molti casi.

Con queste due idee, ciò che non è finito in un'ora ora ha impiegato circa 0,015 secondi.

Probabilmente ci sono molti altri piccoli trucchi che possono accelerare le prestazioni, ma a questo punto ho iniziato a preoccuparmi della mia capacità di giocare a golf. Non sono ancora contento del golf, quindi probabilmente ci tornerò più avanti!

Tempi

Ecco un po 'di codice di prova, che ti invito a provare 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;
}

Ho eseguito i casi di test dell'OP su un laptop dotato di un chip Intel Core i7 da 1,7 GHz, con un'impostazione di ottimizzazione di -Ofast. La simulazione ha riportato un picco di 712 KB richiesti. Ecco un esempio di esecuzione di ogni caso di test, con i tempi:

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

Nel golf, ho colpito le prestazioni piuttosto significativamente, e poiché alla gente sembrava piacere la velocità bruta (0,013624 s per completare tutti i casi di test combinati) della mia precedente soluzione a 618 byte, la lascerò qui come riferimento:

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

L'algoritmo stesso è invariato, ma il nuovo codice si basa su divisioni e alcune operazioni bit per bit più complicate che finiscono per rallentare il tutto.


Stavo pensando di pubblicare una sfida con il codice più veloce su un argomento simile, ma sembra che non debba più farlo. 0,01 secondi e 712 KB è semplicemente sorprendente.
Dennis,

Questo è semplicemente fantastico!
Kirbyfan64sos,

Guardando oltre la tua spiegazione, che diamine è best_found? Viene menzionato solo due volte, una volta quando viene utilizzato nel condizionale e l'altro quando viene ripristinato.
Kirbyfan64sos,

Osservando la sorgente C, sembra che best_foundsia impostato su best_length + current_depth. Probabilmente dovresti menzionarlo nella spiegazione!
Kirbyfan64sos,

@ kirbyfan64sos best_foundè un numero intero globale che descrive la lunghezza della sottostringa comune più lunga trovata in un dato punto dell'esecuzione. Lo inserirò nella spiegazione!
BrainSteel,

1

Python 2, 285

Codice:

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

Spiegazione:

Questa è una funzione ricorsiva. sè il personaggio che stiamo cercando. acontiene un elenco di stringhe tagliate dopo s. bcontiene un elenco di stringhe non ancora elaborate. frestituisce la stringa comune più lunga.

La prima condizione controlla se abbiamo finito di esaminare tutte le stringhe. in tal caso, significa che sè un personaggio comune, e ritorna se cerca personaggi più comuni.

La seconda condizione verifica se non iniziamo a passare alcuna stringa, il che significa che non abbiamo nemmeno un carattere ( a==[]è equivalente a s==''). in tal caso controlliamo ogni carattere della prima stringa in b.

L'ultima linea si muove la prima stringa in ba a, trovando ogni occorrenza di squesta corda.

Alla prima chiamata, sdovrebbe essere una stringa vuota. adovrebbe essere un elenco vuoto e bdovrebbe contenere tutte le stringhe.


2
Dovresti usare gli argomenti predefiniti in modo che solo le stringhe debbano essere fornite alla funzione, come f(b,s='',a=[]).
febbraio
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.