La tarea
- Se le da una cadena mutable que coincide
[a-z]+( [a-z]+)*
. - Debe mutarlo en la cadena que contiene las mismas palabras, pero en orden inverso, de modo que "hola a todos" se convierta en "a todos allí hola".
- No se le permite usar más que una cantidad constante de memoria adicional (por lo que no debe copiar la cadena completa ni ninguna palabra completa en un búfer que acaba de asignar).
- No hay limitaciones de tiempo. Ser irremediablemente ineficiente no dañará su puntaje.
- Si su idioma de elección no permite la mutación de cadenas, las matrices de caracteres son un sustituto aceptable.
Tu puntuación
- Su puntaje se cuenta únicamente en la cantidad de asignaciones que realiza para encadenar elementos (los puntajes pequeños son mejores). Si usa una función de biblioteca que escribe en la cadena, sus escrituras también cuentan.
- Suponga que el número de asignaciones que necesita para la entrada s es n (s) . Entonces su puntaje es el máximo (pedante, supremum) sobre todas las entradas s (que coinciden con la expresión regular especificada anteriormente) de n (s) / longitud (s) . Si no puede calcular esto con precisión, puede usar el límite superior más bajo que pueda probar.
- Puede romper un empate si puede probar que su algoritmo usa menos tareas asintóticamente (esto puede suceder incluso si tiene el mismo puntaje, ver más abajo). Si no puede hacer esto, puede romper un empate al mostrar que usa menos memoria adicional. Sin embargo, la primera condición de desempate siempre tiene prioridad.
- Para algunas entradas, cada carácter debe cambiar, por lo que no es posible obtener una puntuación inferior a 1.
- Puedo pensar en un algoritmo simple con puntaje 2 (pero no lo estoy ingresando).
Notas sobre suprema y lazos
- Un supremum de un conjunto de números es el número más pequeño que no es más pequeño que ninguno de ellos. Esto es muy parecido al máximo de un conjunto, excepto que algunos conjuntos infinitos como {2/3, 3/4, 4/5, 5/6, ...} no tienen un elemento máximo único, pero aún tendrán un supremum, en este caso 1.
- Si logra "guardar" solo un número constante de asignaciones sobre mi algoritmo de puntaje 2 (digamos), su puntaje seguirá siendo 2, porque se acercará arbitrariamente a 2 cuanto mayor sea su entrada. Sin embargo, ganas en el desempate si se trata de eso.
code-challenge
Ben Millwood
fuente
fuente
little-omega(1)
espacio poniéndolo en la pila.O(1)
espacio adicional. NecesitaO(log n)
espacio para almacenar una posición de índice, ya que un entero de k bits solo puede almacenar en ellos cadenas de una longitud de hasta2^k
. Limitar la longitud de las cadenas hace que el desafío sea bastante inútil, ya que cada algoritmo requeriríaO(1)
espacio de esta manera.Respuestas:
Python, Puntuación:
21.51.25Esta es la combinación directa entre la respuesta de primo y mi respuesta. ¡Así que los créditos también para él!
La prueba aún está en progreso, ¡pero aquí está el código para jugar! Si puede encontrar un contraejemplo de puntaje mayor a 1.25 (o si hay un error), ¡hágamelo saber!
Actualmente el peor de los casos es:
donde hay exactamente n de cada una de las letras "a", "b", "c" y "" (espacio), y exactamente dos "d" s. La longitud de la cadena es 4n + 2 y el número de asignaciones es 5n + 2 , dando una puntuación de 5/4 = 1.25 .
El algoritmo funciona en dos pasos:
k
tal questring[k]
ystring[n-1-k]
son límites de palabrasstring[:k]+string[n-1-k:]
(es decir, concatenación del primerk
y último carácterk
) con una pequeña modificación.donde
n
es la longitud de la cadena.La mejora que brinda este algoritmo proviene de la "pequeña modificación" en el Paso 2. Es básicamente el conocimiento de que en la cadena concatenada, los caracteres en la posición
k
y losk+1
límites de las palabras (lo que significa que son espacios o el primer / último carácter de una palabra), y así podemos reemplazar directamente los caracteres en posiciónk
yk+1
con el carácter correspondiente en la cadena final, guardando algunas asignaciones. Esto elimina el peor caso del algoritmo de inversión de palabras del hostHay casos en los que no podemos encontrarlos
k
, en ese caso, simplemente ejecutamos el "algoritmo de inversión de cualquier palabra" en toda la cadena.El código es largo para manejar estos cuatro casos al ejecutar el algoritmo de inversión de palabras en la cadena "concatenada":
k
no se encuentra (f_long = -2
)string[k] != ' ' and string[n-1-k] != ' '
(f_long = 0
)string[k] != ' ' and string[n-1-k] == ' '
(f_long = 1
)string[k] == ' ' and string[n-1-k] != ' '
(f_long = -1
)Estoy seguro de que el código puede acortarse. Actualmente es largo porque al principio no tenía una imagen clara de todo el algoritmo. Estoy seguro de que uno puede diseñarlo para que se represente en un código más corto =)
Ejecución de muestra (primero es mío, segundo es primo):
Puede ver que el puntaje es casi el mismo, excepto por el peor caso del algoritmo de inversión de palabras del host en el tercer ejemplo, para el cual mi enfoque arroja un puntaje menor a 1.25
Python, Puntuación: 1.5
El número exacto de tareas puede ser aproximado por la fórmula:
siendo el peor de los casos:
con 55 asignaciones en cuerda con longitud 37.
La idea es similar a la anterior, es solo que en esta versión intenté encontrar el prefijo y el sufijo en los límites de las palabras con una diferencia de longitud como máximo 1. Luego ejecuté mi algoritmo anterior en ese prefijo y sufijo (imagínelos como concatenados) . Luego continúe en la parte no procesada.
Por ejemplo, para el peor de los casos anteriores:
primero haremos una inversión de palabras en "ab" y "c" (4 asignaciones) para ser:
Sabemos que en el límite solía ser espacio (hay muchos casos que deben manejarse, pero puede hacerlo), por lo que no necesitamos codificar el espacio en el límite, esta es la principal mejora del algoritmo anterior .
Luego, finalmente corremos en los cuatro personajes del medio para obtener:
en total 8 asignaciones, lo óptimo para este caso, ya que los 8 caracteres cambiaron.
Esto elimina el peor caso en el algoritmo anterior ya que se elimina el peor caso en el algoritmo anterior.
Vea un ejemplo de ejecución (y una comparación con la respuesta de @ primo: la suya es la segunda línea):
la respuesta de primo es generalmente mejor, aunque en algunos casos puedo tener 1 punto de ventaja =)
También su código es mucho más corto que el mío, jaja.
Python, Puntuación: asintóticamente 2, en caso normal mucho menos
código antiguo eliminado debido a restricciones de espacio
La idea es iterar a través de cada índice, y para cada índice
i
, que toma el carácter, calcular la nueva posiciónj
, memorizar el carácter en la posiciónj
, asigne el carácter eni
aj
, y repita con carácter en el índicej
. Como necesitamos la información de espacio para calcular la nueva posición, codifico el espacio antiguo como la versión en mayúscula de la nueva letra y el nuevo espacio como '@'.fuente
length(string)/3
forzar que cada palabra en el peor de los casos tenga al menos una longitud 2 de alguna manera), entonces la puntuación será menor que 2 (en el ejemplo anterior será 1.67)if any(process_loop(...) for j in range(...))
¿No deberían contarse las asignaciones de estos bucles de proceso?dry_run
parámetro se establece en un valor distinto de cero (el valor eni
). Dentro deprocess_loop
, sidry_run
no es cero, no hará ninguna asignación.Perl, puntaje 1.3̅
Para cada carácter no espacial se realiza una asignación, y para cada carácter espacial dos asignaciones.
Debido a que los caracteres de espacio no pueden sumar más de la mitad del número total de caracteres, el puntaje del peor de los casos es 1.5 .El algoritmo no ha cambiado, pero puedo demostrar un límite superior inferior. Hagamos dos observaciones:
Entonces se puede ver que el 'peor caso' teórico con 1/2 espacios asintóticamente no es el peor de los casos:
ab c d e f g h i ...
De hecho, es un caso bastante bueno.
Para evitar la observación uno y dos anteriores, cada palabra de un carácter necesitaría reposicionarse en el medio de una palabra de tres o más caracteres de largo. Esto sugeriría el peor de los casos que contiene asintóticamente 1/3 de espacios:
a bcd a bcd a ... bc
O, de manera equivalente, solo palabras de dos caracteres:
a bc de fg hi jk ...
Como el peor de los casos contiene 1/3 de espacios asintóticamente, el puntaje del peor de los casos se convierte en 1.3̅ .
Editar: se agregó un contador de intercambio y la relación.
La entrada se toma de stdin. Uso de la muestra:
Método
Para comenzar, el primer carácter de la cadena se mueve a su destino final. El personaje recién reemplazado se mueve a su destino, etc. Esto continúa hasta que se cumpla una de dos condiciones:
Cuando esto ocurre, el personaje no se intercambia con el espacio, sino más bien en la posición de espejo del espacio. El algoritmo continúa desde esa posición.
Cuando el objetivo regresa a la posición inicial del ciclo actual, se necesita encontrar el siguiente carácter sin cambiar (o más bien, cualquier carácter sin cambiar). Para hacer esto bajo constantes restricciones de memoria, todos los intercambios que se han realizado hasta este punto se remontan.
Después de esta fase, cada personaje no espacial se ha movido como máximo una vez. Para finalizar, todos los caracteres de espacio se intercambian con los caracteres en sus posiciones espejo, lo que requiere dos operaciones de asignación por espacio.
fuente
Ruby, puntaje 2
Como iniciador, un algoritmo muy básico. Primero invierte toda la cadena y luego invierte cada palabra de la cadena nuevamente. En el peor de los casos (una palabra, número par de caracteres) la puntuación se convierte en 2.
Uso:
fuente
C ++: Puntuación 2
fuente
Rebol
No tengo claro el puntaje para esto. No hay asignación directa de cadenas en este código. Todo lo maneja el
reverse/part
que realiza la inversión en el lugar dentro e inicialmente en general la cadena.Algunos detalles sobre el código:
Pase por la cadena (
series
) hasta que alcance eltail?
Primera vez en el bucle, haga el reverso completo de la cadena -
reverse/part series tail series
(que es lo mismo quereverse series
)Luego invierta cada palabra encontrada en otras iteraciones:
reverse/part series find series space
Una vez que la palabra agotada se encuentra, regresa
tail series
para que invierta la última palabra de la cadena.reverse/part series tail series
Rebol permite atravesar una cadena a través de un puntero interno . Puedes ver esto en
series: next f
(mover el puntero al espacio después del comienzo de la siguiente palabra) yseries: head series
(restablece el puntero de nuevo a la cabeza).Ver serie para más información.
Ejemplo de uso en la consola Rebol:
fuente
C: Puntuación 2
Esto simplemente voltea la cadena completa una vez y luego invierte cada palabra.
fuente
Python: puntaje 2
Casi idéntico al algoritmo de Howard, pero realiza los pasos de inversión a la inversa (primero voltea las palabras y luego voltea toda la cadena). Utiliza la memoria adicional es 3 variables byte-size:
i
,j
, yt
. Técnicamente,find
ylen
están utilizando algunas variables internas, pero podrían reutilizari
oj
sin ninguna pérdida de función.edición rápida: guardar en asignaciones de cadenas intercambiando solo cuando los caracteres difieren, por lo que puedo obtener algunos puntos adicionales de la nota # 2.
fuente
Lote
Admitiré que no entiendo completamente la puntuación (creo que son dos) ... pero diré: hace lo correcto .
La entrada se toma como primer valor de entrada estándar y, por lo tanto, debe estar entre comillas:
llame a:
script.bat "hello there everyone"
Salida:
everyone there hello
.Quizás alguien más pueda calificarme (suponiendo que, de alguna otra manera, no me haya descalificado).
fuente
Javascript
Uso:
Tengo la extraña sensación de que me perdí algo ...
fuente