Esta tarea es generar la ruta más corta a un archivo, después de la expansión global.
¿Qué es el globbing de conchas? En la mayoría de los shells, puede usar el *
personaje en una ruta para representar cualquier personaje en la posición. Por ejemplo, si el directorio foo
contiene archivos bar
baz
y asdf
, luego foo/b*
se expandirá a foo/bar foo/baz
.
Ahora, digamos que el directorio actual contiene un archivo llamado ihavealongname
y nada más. Si quiero hacer referencia a este archivo, podría escribir *
, que representará solo ese archivo, en lugar de escribir el nombre completo.
Si el directorio también contiene un archivo llamado ialsohavealongname
, no puedo hacerlo *
, ya que coincidirá con ambos archivos. Lo que tendría que hacer, al menos ih*
,.
El *
patrón también funciona para hacer coincidir directorios sobre el archivo que estoy buscando. Si solo hay dos directorios foo
y bar
, pero foo
contiene solo un archivo baz
y bar
contiene un archivo asdf
, puedo coincidir foo/baz
con */baz
. O, aún más concisamente */b*
. Si bar
estuviera vacío, */*
funcionaría.
Su tarea: Dada una serie de rutas de cadenas que representan el "directorio actual" y una ruta de destino única, genera la cadena más corta posible que se expandiría solo a esa ruta de destino después de expandir * s.
La ruta de destino se puede tomar como su propia cadena, como un índice en la matriz de rutas, como el primer elemento en la matriz de rutas pasadas, o de alguna otra manera conveniente que no sea codificación rígida. Pregunte en comentarios si no está seguro.
La ruta de destino está garantizada para estar presente en el "directorio actual".
Puede suponer que todas las rutas contienen solo ASCII alfanuméricos (y /
s). Puede tomar como rutas de entrada que están enraizadas (comienzan con /
) o relativas (no comienzan con /
).
Si hay múltiples posibilidades igualmente cortas, devuelva una o todas ellas.
Este es el código de golf , ¡gana la menor cantidad de bytes!
Casos de prueba , gracias a Kevin Cruijssen .
fuente
*
,?
,[
etc?*
y ejecutaría Perlglob
para obtener todos los nombres de archivo que puedan ser relevantes (por ejemplo, sefoo/bar/baz
convierte en*/*/*
). Después de eso se convierte en un desafío de procesamiento de cadenas. Y ese desafío ya es bastante difícil. Creo que este desafío sería más limpio ya que "dada una lista de/
rutas alfanuméricas (y ) relativas, encuentre el globo más corto que coincida solo con esta ruta objetivo existentea*f
para seleccionarazzf
deazzf
,azzg
,bzzf
. Extender a voluntad aa*b*c
etc.Respuestas:
Perl 5 ,
136107102 bytesIncluye
+2
paran0
Dar una lista de archivos en STDIN. Se supone que el primero es el archivo de destino
Solo el código sin hacer que las nuevas líneas sean literales:
Se bloquea intencionalmente después de imprimir la solución.
Todavía parece demasiado largo (el uso de
$a
y1/0
son muy incómodos), pero es un comienzo y debería ser razonablemente eficiente.Pruébalo en línea!
Cómo funciona
El programa crea globos candidatos al crecerlos desde atrás hacia adelante, comenzando con la cadena vacía. Esto se hace de una primera forma de anchura, por lo que primero pegotes de longitud 0 se trató (sólo ``), a continuación, la longitud 1 (como
t
,i
,*
), junto longitud 2 (comofb
,i*
,*g
,**
), junto longitud 3 y así sucesivamente hasta que una Se encuentra un globo que solo coincide con la primera ruta. Este será el globo más corto que resuelva el problema (pueden existir otros de la misma longitud).Los globos de longitud
n+1
se generan a partir de los globos de longitudn
anteponiendo cada personaje de la lista de caminos y también*
delante de cada globo de longitudn
. Así por ejemplo, longitud 3 pegote*i*
contribuirá longitud de 4 globosf*i*
,o*i*
,o*i*
,/*i*
,b*i*
...s*i*
,t*i*
y finalmente**i*
. Tenga en cuenta que cada carácter de la lista de rutas de entrada se antepone incluso si aparece varias veces o no tiene ningún sentido porque conduce a algo que nunca puede coincidir.Hacer esto ingenuamente conduciría a una explosión combinatoria. Es por eso que cada glob candidato es evaluado por su utilidad al determinar en qué puntos de las rutas podría coincidir si el glob se usara al final de un glob completo. Hago esto insertando un
;
en cada lugar donde es posible una coincidencia. Por ejemplo, para el globt*
obtendré la cadena:Esto representa el "poder distintivo" del globo. Cada globo que tiene exactamente el mismo poder distintivo es igualmente bueno. Si los reemplaza uno al otro al final de un glob completo, todos coincidirán exactamente con los mismos caminos. Así que también puedes usar el más corto.
Entonces, al considerar los
n
globos de longitud , primero miro su poder distintivo. Si se ha visto antes, hubo otro globo de longitudn
o menor que ya se consideró y expandió, por lo que este globo no tiene sentido y se poda. Esto, por ejemplo, eliminará a candidatos como**i*
ya se habrá visto el mismo poder distintivo*i*
. También elimina candidatos imposibles,f*i*
ya que la cadena distintiva no tendrá;
y simplemente ser la lista original de caminos. Solo se aceptará el primer pegote imposible, se considerará que todos los demás tienen el mismo poder distintivo y se podarán. E incluso ese primero no se expandirá realmente, ya que todas las expansiones son aún imposibles y se podarán cuando se consideren. Simularmentein*
será podado pori*
etc.Lo anterior conduce a una poda muy agresiva y, por lo tanto, el programa puede manejar casos complejos en muy poco tiempo. Sin embargo, una gran ineficiencia es que antepone los globos candidatos con todos los caracteres posibles, no solo los que están justo antes de una parte
;
en la ruta de destino de la cadena distintiva. Todos los caracteres añadidos que no están delante de un;
no son un problema, ya que conducen a un globo imposible que se eliminará cuando se considere, pero que todavía deja a los personajes justo antes;
en los otros caminos. Entonces, al final, el programa también crea globos que podrán combinar cualquier combinación de las rutas dadas. No tiene idea de que debería concentrarse en el primer camino.Ahora considere una solución al problema. En el ejemplo dado que podría ser
*/*er/t
. Esto proporciona la siguiente cadena distintiva:Reconozco una solución al tener un
;
en la primera posición (para que coincida con el primer camino) y no tener un;
al comienzo de cualquier otro camino (para que los otros no coincidan)Con el algoritmo explicado, ahora llego al programa real:
Los globos globulares candidatos estarán en una matriz
@a
que recorro usando una variable$a
que contiene el globo que se está considerando actualmente.*
Sin embargo, en lugar de en el globo, lo usaré, por\w*
lo$a
que en realidad es una expresión regular en lugar de un globo. Voy a abusar de una rareza del perl for loop que puede agregar elementos a la matriz que se está enlazando mientras el bucle se está ejecutando y estos nuevos elementos se recogerán en el bucle. Dado que al generar losn+1
globos de longitud todos los globos de longitudn
ya están en la matriz,@a
esto es primero la amplitud.Debido a la
-n0
opción (bucle implícito sobre toda la entrada), la lista de rutas está en$_
una sola cadena grande con cada ruta terminada con una nueva líneaDentro del
{ }
tenemos:Vaya, acabo de destruirlo
$_
y lo necesitaré para el próximo ciclo. Así que envuelva el código de trabajo real dentroEsto coincide con la cadena vacía al comienzo
$_
y le permite ejecutar código para determinar con qué se reemplaza. Si me aseguro de que ese código se evalúe como la cadena vacía$_
, al final permanecerá sin cambios incluso si cambio$_
durantecode
.Volviendo a justo después de que lo reemplazara
$_
por la cadena distintiva:Esto es como:
//
en perl es'defined or
. Es como un corto circuitoor
donde el segundo argumento solo se evalúa si el primero lo esundef
. Y se puede combinar con una tarea como+=
en otros idiomas. Así que si ellos clave$_
en picadillo%seen
esundef
(que es es lo que obtienes cuando se accede a un elemento no existente) sólo entonces ejecutar expresión y asignarlo como valor en la clave$_
. Entonces, si me aseguro deexpression
que no regrese,undef
eso básicamente significa "evaluar la expresión si y solo si es la primera vez que vemos esa cadena distintiva en particular". Y debido a que$_
se garantiza que contiene un\n
, de hecho es seguro abusar del hash global de Perl para almacenar las cadenas distintivas, por lo que en$$_
lugar de$seen{$_}
Para el
expression
uso:Básicamente "Para cada carácter (excepto la nueva línea) en la cadena distintiva y también lo
*
antepone al globo actual y lo empuja en el conjunto de globos candidatos". Excepto que utilizo\w*
para*
obtener una expresión regular válida (podría usar en''
lugar de""
deshacerme de una barra invertida pero no pude ejecutar mi código desde la línea de comandos). Tenga en cuenta que esto también recoge el;
y los agrega a los globos globulares candidatos, pero cuando más tarde los pruebe en el restaurado$_
que no tiene;
eso, volverá a ser un globo imposible y se podará.Tenga en
/^;/>/\n;/
cuenta que tiene un valor equivalente a la cadena vacía en caso de que aún no se encuentre una solución, por lo que funcionará como una cadena de reemplazo vacía y$_
se restauraráfuente
-E
activa el último nivel de idioma. Necesita al menos Perl5.10.0
para poder usarsay
. Así que ponuse 5.10.0;
en la sección del encabezado y funcionará. Las opciones para establecer el nivel de idioma cuentan como gratuitas de todos modos, incluso si no pudieras hacerlo también usando-E
. De hecho, todas las opciones cuentan como gratuitas hoy en día (por lo que ni siquiera tengo que contarn0
), pero considero que es demasiado indulgente para Perl1/
solución es válida. Necesito recordar eso también ...Java 10,
854824796738728703688655652647624 bytesQué desastre. Ciertamente, este no es un desafío fácil en Java.
Definitivamente se puede jugar un par de cientos de bytes, pero me alegra que finalmente esté funcionando ahora.Te lo dije. :)-5 bytes gracias a @ceilingcat .
-23 bytes cambiando de Java 8 a Java 10
Ingrese como un conjunto de cadenas de rutas de archivos (con directorios como elementos separados, y todos los elementos que contienen un inicio
/
), y una cadena con la ruta de archivos de entrada para recortar.Explicación:
Pruébalo en línea. (Los casos de prueba con
ialsohavealongname
/ihavealongnameaswell
tienen una longitud ligeramente reducida ys.add(x.replaceAll("~+","\\*"));
se han reemplazado{s.remove(x);s.add(x.replaceAll("~+","\\*"));}
por trabajar en 5-10 segundos con TIO, en lugar de agotar el tiempo de espera después de más de 60 segundos).Explicación general adicional:
Ejemplo: tomemos
/foo, /foo/bar, /foo/barber, /foo/bar/test, /foo/barber/test, /foo/barber/testing, /foo/barber/coding, /foo/test
como rutas de archivo dadas, yfoo/bar/test
como ruta de entrada de archivo para recortar.1) Comienzo dividiendo la entrada de ruta de archivo por
/
, y genero todos los recortes de archivo de estas palabras separadas:2) Luego genero todas las permutaciones con estas palabras en el mismo orden (volviendo a aplicar el
/
intermedio y al frente):3) Luego hago un bucle sobre los elementos de esta lista anterior y valido si solo coincide con una única ruta de archivo en la matriz de entrada de rutas de archivo. (Hago esto marcando dos cosas: si la cantidad de barras es la misma y si coincide con la expresión regular donde
*
se reemplaza cada una.*
).Si lo hace: mantenga el (primero) más corto, que al final devolveremos.
fuente
>>>
? Sé que>>
es bitwise desplazamiento a la derecha.>>>
actúa igual que>>
. Pero para enteros negativos cambia el bit de paridad a 0 (puede ver algunos ejemplos aquí en la sección " >> vs >>> " ).-1>>>1
es solo una variante más corta deInteger.MAX_VALUE
(y1<<31
seríaInteger.MIN_VALUE
).