Verifique se uma sequência é uma mistura de gêmeos

10

Explicação

Duas seqüências de caracteres podem ser embaralhadas, intercalando suas letras para formar uma nova sequência, assim como duas pilhas de cartas podem ser embaralhadas para formar uma única pilha.

Por exemplo, as strings HELLOe WORLDpodem ser embaralhadas para formar HWEOLRLLOD, ou HEWORLLLDO, ou talvez simplesmente HELLOWORLD.

É não um embaralhamento se a ordem original das letras não é preservado. Por exemplo, o Din WORLDnunca pode aparecer antes do Rembaralhamento depois. Isso significa que EHLLOWRDLO, por exemplo, não é um embaralhamento HELLOe WORLD, embora contenha todas as letras originais.

Uma corda é um embaralhamento de gêmeos se puder ser formada embaralhando duas cordas idênticas. Por exemplo, ABACBDECDEé um embaralhar de gêmeos porque pode ser formado embaralhando ABCDEe ABCDE. DBEACBCADEnão é um embaralhar de gêmeos porque não pode ser formado embaralhando duas cordas idênticas.

Detalhes do Programa

Dada uma sequência de entrada, produza, 0se não for um shuffle de gêmeos, e produza uma das strings duplas, se for um shuffle de gêmeos.

Você pode supor que a sequência de entrada tenha um comprimento inclusivo entre quatro e vinte caracteres e seja composta inteiramente de caracteres alfabéticos maiúsculos. Ele deve ser executado em um período de tempo razoável, digamos, em menos de 10 minutos.

Isso é código de golfe, então a solução mais curta vence.

Exemplo de E / S

> ABACBDECDE
ABCDE

> DBEACBCADE
0

> FFFFFF
FFF

> FFGGG
0

> ABBA
0

> AABB
AB

> AABAAB
AAB

Eu tenho uma implementação de exemplo (sem golfe) .

Peter Olson
fonte
A sequência de exemplo FGG viola a afirmação that the input string has a length inclusively between four and twenty characterse não me diga "nunca confie na entrada do usuário!", "Nunca confie nas especificações!"
usuário desconhecido
@userunknown Isso é tão embaraçoso! Eu editei FFGGGpara torná-lo consistente.
Peter Olson
11
Por curiosidade, alguém pode encontrar uma solução com complexidade subexponencial de pior caso, ou provar que não existe?
Ilmari Karonen

Respostas:

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

Explicação:

A maior parte do trabalho está sendo realizada na partitionsfunção. Ele funciona gerando recursivamente todas as partições (a, b)do final da lista e, em seguida, usando a mônada da lista para acrescentar o elemento inicial xa cada uma delas e reunir todos os resultados.

findMatchfunciona filtrando essa lista para que apenas as partições onde as subsequências são iguais permaneçam. Em seguida, ele retorna a primeira subsequência na primeira partição. Se não houver nenhum, a lista estará vazia; portanto, o "0"anexo no final será retornado.

main apenas lê a entrada, a alimenta através dessas duas funções e a imprime.

hammar
fonte
Para aqueles de nós que não sabem ler Haskell, você dará uma explicação?
precisa saber é o seguinte
11
@ Mr.Wizard: Veja a edição.
hammar
Eu acho que criei algo bastante semelhante, embora não tão curto, mas joguei de uma maneira tola que o tornou um fracasso completo. Você se importa se eu implementar esse algoritmo no Mathematica?
Mr.Wizard
4

R, 113 caracteres

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 uma função que pega a string):

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

A solução depende da combnfunção que gera todas as combinações de índices como colunas em uma matriz. applyaplica uma função a cada coluna (dimensão 2) na matriz e retorna um vetor de cadeias ou zeros. maxentão encontre a maior string (que supera 0).

Um recurso interessante em R é a capacidade de selecionar um subconjunto de um vetor dado um vetor de índices e, em seguida, selecionar o complemento desse subconjunto negando os índices:x[i] == x[-i]

Tommy
fonte
Fiz algumas melhorias incrementais e reduzi a contagem de caracteres.
Tommy
3

Mathematica, 87

Isso é diretamente baseado no post do hammar, mas espero que seja distinto o suficiente para merecer a publicação.

<<Combinatorica`

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

Teste:

f /@ {"ABACBDECDE", "DBEACBCADE", "FFFFFF", "FGG", "ABBA", "AABB", "AABAAB"}
{"ABCDE", 0, "FFF", 0, 0, "AB", "AAB"}
Mr.Wizard
fonte
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));}

usando a primeira pesquisa recursiva em profundidade

Eu posso torná-lo mais rápido com uma int i = min(a.length,b.length);if(a[0..i]!=b[0..i])return "0";cláusula de guarda

catraca arrepiante
fonte
No IDEONE, falhei ao tentar iniciar o programa void main(){writeln(c("ABCADABCAD"));}- apenas uma versão diferente de D, minha culpa, outra coisa? O que há com "ABCABCA"?
usuário desconhecido
você precisará importar std.stdio; para IO
catraca anormal
1

Ruby, 89 caracteres

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

Esse código implementa um algoritmo de pesquisa recursiva simples. A entrada deve ser fornecida no STDIN.

Howard
fonte
1

Perl, 68 caracteres

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

A cadeia de entrada assumida como estando na $_variável, a saída é o valor da expressão. Novas linhas à direita na entrada são ignoradas. Você pode executar isso na linha de comando da seguinte maneira:

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

Esse código usa o mecanismo regexp do Perl (e especificamente seu recurso de execução de código incorporado ) para fazer o backtracking. Basicamente, ele corresponde a seqüência de entrada contra a regexp ^((.+))+$, mantendo o controle das submatches páginas ímpares e pares numeradas $xe $,, e rejeitando o jogo no final, se os dois não são iguais.

Ilmari Karonen
fonte
Isso tem o resultado correto para AABAAB?
Peter Olson
Sim. (Na verdade, AABAABé um caso fácil para esta solução, uma vez que o grupo externo só precisa corresponder duas vezes Levei muito mais tempo para obtê-lo a cabo. AABBCerta.)
Ilmari Karonen
1

Python, 168 caracteres

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())
Steven Rumbalski
fonte