Comprueba si una cuerda es una mezcla de gemelos

10

Explicación

Se pueden barajar dos cadenas intercalando sus letras para formar una nueva cadena, al igual que dos pilas de cartas se pueden barajar para formar una sola pila.

Por ejemplo, las cadenas HELLOy WORLDse pueden mezclar para formar HWEOLRLLOD, o HEWORLLLDO, o quizás simplemente HELLOWORLD.

Es no una reproducción aleatoria si la orden original de las cartas no se conserva. Por ejemplo, la Dde WORLDque no puede aparecer siempre antes del Rdespués de haber sido barajadas. Esto significa que EHLLOWRDLO, por ejemplo, no es una mezcla de , HELLOy WORLDaunque contiene todas las letras originales.

Una cadena es una mezcla de gemelos si se puede formar barajando dos cadenas idénticas. Por ejemplo, ABACBDECDEes una mezcla de gemelos porque puede formarse barajando ABCDEy ABCDE. DBEACBCADEno es una mezcla de gemelos porque no se puede formar mezclando dos cadenas idénticas.

Detalles del programa

Dada una cadena de entrada, salida 0si no es una combinación aleatoria de gemelos, y salida de una de las cadenas gemelas si es una combinación aleatoria de gemelos.

Puede suponer que la cadena de entrada tiene una longitud inclusive entre cuatro y veinte caracteres y está compuesta completamente por caracteres alfabéticos en mayúsculas. Debería poder ejecutarse en un tiempo razonable, digamos, menos de 10 minutos.

Este es el código de golf, por lo que gana la solución más corta.

Ejemplo de E / S

> ABACBDECDE
ABCDE

> DBEACBCADE
0

> FFFFFF
FFF

> FFGGG
0

> ABBA
0

> AABB
AB

> AABAAB
AAB

Tengo un ejemplo (no golfizado) de implementación .

Peter Olson
fuente
La cadena de ejemplo FGG viola la afirmación that the input string has a length inclusively between four and twenty characters, y no me digas "¡nunca confíes en la entrada del usuario!", "¡Nunca confíes en las especificaciones!"
usuario desconocido el
@userunknown ¡Eso es tan vergonzoso! Lo edité FFGGGpara que sea consistente.
Peter Olson
1
Solo por curiosidad, ¿alguien puede encontrar una solución con una complejidad de tiempo sub-exponencial en el peor de los casos, o demostrar que no hay ninguna?
Ilmari Karonen

Respuestas:

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

Sin golf:

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

Explicación:

La mayor parte del trabajo se realiza en la partitionsfunción. Funciona generando recursivamente todas las particiones (a, b)de la cola de la lista, y luego usando la mónada de la lista para anteponer el elemento inicial xa cada una de ellas y reunir todos los resultados.

findMatchfunciona filtrando esta lista para que solo permanezcan las particiones donde las subsecuencias son iguales. Luego devuelve la primera subsecuencia en la primera partición. Si no queda ninguno, la lista está vacía, por lo que "0"se devuelve el agregado al final.

main solo lee la entrada, la alimenta a través de estas dos funciones y la imprime.

hammar
fuente
Para aquellos de nosotros que no podemos leer Haskell, ¿darán una explicación?
Mr.Wizard
1
@ Mr.Wizard: ver edición.
hammar
Creo que se me ocurrió algo bastante similar, aunque no tan corto, pero arrojé un tipo tonto que lo convirtió en un completo fracaso. ¿Te importa si implemento este algoritmo en 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))

Sin golf (y en su lugar, una función que toma la cadena):

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 solución se basa en la combnfunción que genera todas las combinaciones de índices como columnas en una matriz. applyluego aplica una función a cada columna (dimensión 2) en la matriz y devuelve un vector de cadenas o ceros. maxluego encuentre la cadena más grande (que triunfa 0).

Una característica interesante en R es la capacidad de seleccionar un subconjunto de un vector dado un vector de índices, y luego seleccionar el complemento de ese subconjunto negando los índices:x[i] == x[-i]

Tommy
fuente
Hice algunas mejoras incrementales y recuento reducido de char.
Tommy
3

Mathematica, 87

Esto se basa directamente en la publicación de hammar, pero es de esperar que sea lo suficientemente distinto como para merecer publicación.

<<Combinatorica`

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

Prueba:

f /@ {"ABACBDECDE", "DBEACBCADE", "FFFFFF", "FGG", "ABBA", "AABB", "AABAAB"}
{"ABCDE", 0, "FFF", 0, 0, "AB", "AAB"}
Señor mago
fuente
1

re

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 la búsqueda recursiva en profundidad primero

Puedo hacerlo más rápido con una int i = min(a.length,b.length);if(a[0..i]!=b[0..i])return "0";cláusula de guardia

monstruo de trinquete
fuente
En IDEONE, fallé al intentar iniciar el programa void main(){writeln(c("ABCADABCAD"));}, solo una versión diferente de D, mi culpa, ¿algo más? ¿Qué pasa con "ABCABCA"?
Usuario desconocido el
deberás importar std.stdio; para el IO
monstruo de trinquete
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,'','']

Este código implementa un algoritmo de búsqueda recursiva simple. La entrada debe darse en STDIN.

Howard
fuente
1

Perl, 68 caracteres

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

Se supone que la cadena de entrada está en el $_ variable, la salida es el valor de la expresión. Las nuevas líneas finales en la entrada se ignoran. Puede ejecutar esto desde la línea de comando de esta manera:

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

Este código utiliza el motor regexp de Perl (y específicamente su función de ejecución de código incrustada ) para realizar el seguimiento. Básicamente, hace coincidir la cadena de entrada con la expresión regular ^((.+))+$, haciendo un seguimiento de las coincidencias pares e impares en $xy $,, y rechazando la coincidencia al final si las dos no son iguales.

Ilmari Karonen
fuente
¿Tiene esto el resultado correcto AABAAB?
Peter Olson
Si lo hace (De hecho, AABAABes un caso fácil para esta solución, ya que el grupo externo solo necesita coincidir dos veces. Me tomó mucho más tiempo lograr que se maneje AABBbien).
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
fuente