Controlla se una stringa è un riordino di due gemelli


10

Spiegazione

Due stringhe possono essere mischiate mescolando le loro lettere per formare una nuova stringa, proprio come due pile di carte possono essere mescolate per formare una singola pila.

Ad esempio, le stringhe HELLOe WORLDpossono essere mescolate per formare HWEOLRLLOD, o HEWORLLLDO, o forse semplicemente HELLOWORLD.

E ' non è uno shuffle se l'ordine originale delle lettere non si conserva. Ad esempio, Din WORLDnon può mai apparire prima che il Rdopo venga mischiato. Ciò significa che EHLLOWRDLO, per esempio, non è un miscuglio di HELLOe WORLD, sebbene contenga tutte le lettere originali.

Una stringa è una mescolanza di gemelli se può essere formata mescolando due stringhe identiche. Ad esempio, ABACBDECDEè un miscuglio di gemelli perché può essere formato mescolando ABCDEe ABCDE. DBEACBCADEnon è un miscuglio di gemelli perché non può essere formato mescolando due stringhe identiche.

Dettagli del programma

Data una stringa di input, output 0se non è un shuffle di gemelli e output di una delle stringhe gemelle se è un shuffle di gemelli.

Si può presumere che la stringa di input abbia una lunghezza inclusivamente compresa tra quattro e venti caratteri ed è composta interamente da caratteri alfabetici maiuscoli. Dovrebbe essere in grado di funzionare in un tempo ragionevole, diciamo, meno di 10 minuti.

Questo è il golf del codice, quindi vince la soluzione più breve.

Esempio di I / O

> ABACBDECDE
ABCDE

> DBEACBCADE
0

> FFFFFF
FFF

> FFGGG
0

> ABBA
0

> AABB
AB

> AABAAB
AAB

Ho un'implementazione di esempio (non golfizzata) .


La stringa di esempio FGG viola l'asserzione that the input string has a length inclusively between four and twenty characterse non dirmi "mai fidarsi dell'input dell'utente!", "Mai fidarsi delle specifiche!"
utente sconosciuto

@userunknown È così imbarazzante! L'ho modificato FFGGGper renderlo coerente.
Peter Olson,

1
Solo per curiosità, qualcuno può trovare una soluzione con complessità sub-esponenziale nel caso peggiore, o provare che non ce n'è?
Ilmari Karonen,

Risposte:


4

Haskell, 114

main=getLine>>=putStrLn.f.p;f x=head$[a|(a,b)<-x,a==b]++["0"]
p[]=[([],[])];p(x:y)=do(a,b)<-p y;[(x:a,b),(a,x:b)]

Ungolfed:

main :: IO ()
main = getLine >>= putStrLn . findMatch . partitions

-- | Find the first partition where the two subsequences are
-- equal. If none are, return "0".
findMatch :: [(String, String)] -> String
findMatch ps = head $ [a | (a,b) <- ps, a == b] ++ ["0"]

-- | Return all possible partitions of the input into two
-- subsequences. Preserves the order of each subsequence.
--
-- Example:
-- partitions "AB" == [("AB",""),("B","A"),("A","B"),("","AB")]
partitions :: [a] -> [([a], [a])]
partitions []     = [([], [])]
partitions (x:xs) = do (a, b) <- partitions xs
                       [(x:a, b), (a, x:b)]

Spiegazione:

La maggior parte del lavoro viene svolto nella partitionsfunzione. Funziona generando in modo ricorsivo tutte le partizioni (a, b)della coda dell'elenco e quindi utilizzando la monade elenco per anteporre l'elemento iniziale xa ciascuno di essi e raccogliere tutti i risultati.

findMatchfunziona filtrando questo elenco in modo che rimangano solo le partizioni in cui le sottosequenze sono uguali. Restituisce quindi la prima sottosequenza nella prima partizione. Se non ne rimane nessuno, l'elenco è vuoto, quindi "0"viene restituito l' aggiunta alla fine.

main legge solo l'input, lo alimenta attraverso queste due funzioni e lo stampa.


Per quelli di noi che non sanno leggere Haskell, darai una spiegazione?
Mr.Wizard,

1
@ Mr.Wizard: vedi modifica.
Hammar,

Penso di aver trovato qualcosa di abbastanza simile, anche se non così breve, ma ho gettato in una specie di sciocco che lo ha reso un fallimento completo. Ti dispiace se implemento questo algoritmo in Mathematica?
Mr.Wizard,

4

R, 113 caratteri

l=length(x<-charToRaw(scan(,'')));max(apply(combn(l,l/2),2,function(i)if(all(x[i]==x[-i]))rawToChar(x[i])else 0))

Ungolfed (e invece una funzione che accetta la stringa):

untwin <- function(x) {
  x <- charToRaw(x)
  indMtx <- combn(length(x),length(x)/2)
  res <- apply(indMtx, 2, function(i) {
    if (all(x[i]==x[-i]))
      rawToChar(x[i])
    else
      0
  })
  max(res)
}

untwin("ABACBDECDE") # "ABCDE"
untwin("DBEACBCADE") # 0

La soluzione si basa sulla combnfunzione che genera tutte le combinazioni di indici come colonne in una matrice. applyquindi applica una funzione a ciascuna colonna (dimensione 2) nella matrice e restituisce un vettore di stringhe o zero. maxquindi trova la stringa più grande (che supera 0).

Una caratteristica interessante di R è la capacità di selezionare un sottoinsieme di un vettore dato un vettore di indici, e quindi selezionare il complemento di quel sottoinsieme negando gli indici:x[i] == x[-i]


Ha apportato alcuni miglioramenti incrementali e ridotto il conteggio dei caratteri.
Tommy,

3

Mathematica, 87

Questo si basa direttamente sul post di Hammar, ma si spera che sia abbastanza distinto da meritare il post.

<<Combinatorica`

f=Catch[Cases[Characters@#~KSetPartitions~2,{x_,x_}:>Throw[""<>x]];0]&

Test:

f /@ {"ABACBDECDE", "DBEACBCADE", "FFFFFF", "FGG", "ABBA", "AABB", "AABAAB"}
{"ABCDE", 0, "FFF", 0, 0, "AB", "AAB"}

1

D

string c(string in,string a=[],string b=[]){
    if(in.length==0)return a==b?a;"0";
    auto r=c(in[1..$],a~in[0],b);
    return r=="0"?c(in[1..$],a,b~in[0]):r;
}
void main(){writeln(c(readline));}

utilizzando la prima ricerca ricorsiva di profondità

Posso renderlo più veloce con una int i = min(a.length,b.length);if(a[0..i]!=b[0..i])return "0";clausola di guardia


Su IDEONE, non sono riuscito a provare ad avviare il programma con void main(){writeln(c("ABCADABCAD"));}- solo una versione diversa di D, colpa mia, qualcos'altro? Che dire di "ABCABCA"?
utente sconosciuto

dovrai importare std.stdio; per l'IO
maniaco del cricchetto,

1

Rubino, 89 caratteri

s=->a,x,y{a=="\n"?x==y ?x:?0:[s[b=a[1..-1],x+c=a[0],y],s[b,x,y+c]].max}
$><<s[gets,'','']

Questo codice implementa un semplice algoritmo di ricerca ricorsiva. L'ingresso deve essere dato su STDIN.


1

Perl, 68 caratteri

/^((.+)(?{local($x,$,)=($,,$x.$^N)}))+$(?(?{$o=$,eq$x&&$,})|x)/?$o:0

La stringa di input presuppone di essere nella $_variabile, l'output è il valore dell'espressione. Le nuove righe finali in input vengono ignorate. Puoi eseguirlo dalla riga di comando in questo modo:

perl -lne 'print /^((.+)(?{local($x,$,)=($,,$x.$^N)}))+$(?(?{$o=$,eq$x&&$,})|x)/?$o:0'

Questo codice utilizza il motore regexp di Perl (e in particolare la sua funzione di esecuzione del codice incorporato ) per eseguire il backtracking. Fondamentalmente, abbina la stringa di input al regexp ^((.+))+$, tenendo traccia dei invii dispari e pari $xe $,, e respingendo la corrispondenza alla fine se i due non sono uguali.


Questo ha il risultato corretto per AABAAB?
Peter Olson,

Sì lo fa. (In effetti, AABAABè un caso facile per questa soluzione, dal momento che il gruppo esterno deve solo abbinare due volte. Mi ci è voluto molto più tempo per farlo funzionare AABBbene.)
Ilmari Karonen

1

Python, 168 caratteri

def f(s):
 c=s[0]
 d=i=r=0
 if s==c+c:r=c
 while i+1 and i<=len(s)/2 and not r:
  if i:d=f(s[1:i]+s[i+1:])
  if d:r=c+d
  i=s.find(c,i+1)
 return r
print f(raw_input())
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.