2009-08-24 12 views
5

Mi chiedo se qualcuno conosce l'algoritmo (ottimale?) Per la sottostringa ricorrente non sovrapposta più lunga.Sottostringa non sovrapposta più lunga

Per esempio, nella stringa

ABADZEDGBADEZ

la più lunga ricorrenti sarebbe "BAD". Per inciso, se non c'è un tale risultato, l'algoritmo dovrebbe avvisare che si è verificata una cosa del genere. La mia ipotesi è che questo coinvolga alberi di suffisso.

Sono sicuro che questo deve esistere già da qualche parte. Grazie per l'aiuto!

+0

proprio curious- qual è l'applicazione aziendale per questo? – Beth

+0

Non è un'applicazione aziendale. È legato al trovare il tema in una canzone ed è più una curiosità al momento finché non avrò un progetto che coinvolge questo. =] –

risposta

4

Dal momento che stai applicando questo alla musica, probabilmente non stai cercando corrispondenze al 100%; ci saranno delle discrepanze previste da un'istanza del tema a un altro. Potresti provare a cercare gli algoritmi di analisi della sequenza genica - c'è un sacco di questa varietà di cose in corso lì. Prova BLAST o altri algoritmi di allineamento.

Si potrebbe anche provare la famiglia di algoritmi WinEPI, oltre a varie implementazioni di prefissi di questo specifico set di risultati (questi risultati consentono lacune nella sottostringa, ad esempio ABCID e AFBCD contengono entrambi ABCD). In realtà ho un documento su un algoritmo che potrebbe valere la pena di guardare se ti interesserebbe; Avrei bisogno di ottenere l'autorizzazione alla distribuzione, quindi fammi sapere.

Si noti che questo è in realtà un argomento MOLTO complicato (da fare in modo efficiente) per dataset di grandi dimensioni.

Origine: ricerca per un anno o due su un tema comparabile (rilevamento di temi).

+0

Se potessi concedermi l'accesso, sarebbe apprezzato! –

+0

Penso che stia applicando questo ai testi, quindi penso che stia cercando le corrispondenze al 100%. – las3rjock

+0

@Brandon - Ho richiesto il permesso, vedrò cosa posso fare. @ las3rjock - Non proprio. Per esempio: Ero un uomo sciocco Ero sciocco, uomo Esempio di tema: stupidità passata. Le stringhe non sono una corrispondenza esatta. Inoltre, molti testi hanno punteggiatura diversa e quant'altro. Quindi non sono sicuro che stia cercando una corrispondenza esatta. –

4

Suffix array è una buona struttura dati per risolvere il problema.

C'è una soluzione a questo problema in Programming Pearls di Jon Bentley.

+0

Dove nella programmazione delle perle? –

+0

@Emil H, ** 15.2 Frasi ** –

+1

@Nick Non penso che la stessa soluzione in Programing Pearls possa essere applicata direttamente qui. L'esempio di "BANANA" restituisce "ANA" che si verifica due volte e si sovrappone quindi, contrariamente alle condizioni menzionate da OP. Potrebbe essere necessaria qualche modifica per condizioni non sovrapposte. Che ne dici? –

1

un semplice algoritmo è quello di fare questo:

  • Creare una struttura di dati che rappresenta fette di una stringa; implementare confronto/ordinamento in base alla lingua
  • Creare un elenco di ogni sezione della stringa iniziando con [carattere iniziale, ultimo carattere], [carattere secondario, ultimo carattere], fino a [ultimo carattere, last-character]
  • Ordina questo elenco - O (n log n)
  • Questo porta tutte le sezioni di stringa con prefissi comuni insieme. Puoi quindi scorrere l'elenco, confrontando ogni coppia per vedere quanti caratteri condividono all'inizio e se è maggiore del tuo massimo, prendine nota e impostalo come nuovo massimo

(As l'altra risposta appena pubblicata indica, sto descrivendo un suffisso array qui.)

+0

Questa è ancora forza piuttosto bruta. Mi chiedo se c'è un approccio un po 'più elegante? Credo che un approccio basato sull'albero preserverebbe le informazioni strutturali e fornirà una sorta di informazioni sulla profondità che possono essere rapidamente attraversate per fornire informazioni sulla lunghezza più lunga. –

+0

Con un ordinamento appropriato - vedi l'articolo wikipedia sull'array di suffissi - il tempo di esecuzione è O (n log n) nel peggiore dei casi e solitamente migliore. L'iterazione è O (n), quindi è dominata dal costo di ordinamento. L'evidente forza bruta sta per essere O (n^2) almeno (confrontando ogni coppia possibile). Probabilmente la costruzione di alberi avrà un costo molto più elevato della memoria, con effetti negativi sulle prestazioni reali (considerare la cache, ecc.). –

0

Ok, ecco una pazza idea.

Creare una funzione che determina se esiste una sottostringa ricorrente di lunghezza k in O (n) (dove n è la lunghezza del testo). Questo può essere fatto usando un hash rolling (vedi wikipedia per Rabin-Karp String Matching Algorithm) per generare tutti gli n hash in tempo lineare e usando un hashtable/BST (o una mappa o dict o qualsiasi altra lingua la chiami) per memorizzare le posizioni di sottostringa corrispondenti. Prima di inserire l'attuale hash nella struttura dati, controlliamo se l'abbiamo già visto prima.Se è stato visto prima, cerchiamo semplicemente gli indici in cui è stato generato questo hash e vediamo se la sottostringa corrispondente è una corrispondenza non sovrapposta.

Ora che possiamo trovare una sottostringa di lunghezza k nel tempo O (n), eseguiamo semplicemente una ricerca binaria per trovare il k più grande per il quale possiamo trovare una corrispondenza di sottostringa non sovrapposta usando la nostra funzione.

codice in Python segue

A=23 
MOD=10007 # use a random value in the real world 

def hsh(text): 
    return sum([ord(c)*A**(len(text)-i-1) for i,c in enumerate(text)])%MOD 

def k_substring(text, k): 
    substrings={} 
    cur=hsh(text[:k]) 
    pwr=(A**(k-1))%MOD 
    substrings[cur]=[0] 
    for i in xrange(k,len(text)): 
     to_remove=(ord(text[i-k])*pwr)%MOD 
     to_add=ord(text[i]) 
     cur-=to_remove 
     if cur<0: 
      cur+=MOD 
     cur=(cur*A)%MOD 
     cur=(cur+to_add)%MOD 
     if cur in substrings: 
      lst=substrings[cur] 
      for index in lst: 
       if index+k<=i-k+1 and text[index:index+k]==text[i-k+1:i+1]: 
        return index 
      lst.append(i-k+1) 
     else: 
      substrings[cur]=[i-k+1] 
    return -1 

def longest_substring(text): 
    hi,lo=len(text),0 
    while hi>lo: 
     mid=(hi+lo+1)>>1 
     if k_substring(text,mid)==-1: 
      hi=mid-1 
     else: 
      lo=mid 
    index=k_substring(text,lo) 
    return text[index:index+lo] 

(Scusate se questo non è chiaro. E '6:30 qui e ho davvero bisogno di tornare a letto :))

Problemi correlati