A tarefa
- Você recebe uma sequência mutável que corresponde
[a-z]+( [a-z]+)*
. - Você deve modificá-lo para a string que contém as mesmas palavras, mas na ordem inversa, para que "olá lá todos" se torne "todos lá olá".
- Você não tem permissão para usar mais do que uma quantidade constante de memória adicional (portanto, não é necessário copiar a cadeia inteira ou nenhuma palavra inteira em um buffer que você acabou de alocar).
- Não há restrições de tempo. Ser irremediavelmente ineficiente não prejudicará sua pontuação.
- Se o seu idioma de escolha não permitir a mutação de cadeias, matrizes de caracteres são um substituto aceitável.
Sua pontuação
- Sua pontuação é contada apenas com o número de atribuições feitas aos elementos de sequência (as melhores pontuações são as melhores). Se você usar uma função de biblioteca que grava na cadeia, suas gravações também contam.
- Suponha que o número de atribuições necessárias para a entrada s seja n (s) . Então sua pontuação é o máximo (pedanticamente, supremo) em todas as entradas s (correspondendo ao regex especificado acima) de n (s) / comprimento (s) . Se você não puder calcular isso com precisão, poderá usar o limite superior mais baixo que puder provar.
- Você pode quebrar o empate se puder provar que seu algoritmo usa assintoticamente menos atribuições (isso pode acontecer mesmo se você tiver a mesma pontuação, veja abaixo). Se você não puder fazer isso, poderá quebrar o empate mostrando que usa menos memória adicional. No entanto, a primeira condição de desempate sempre tem precedência.
- Para algumas entradas, todos os caracteres precisam mudar, portanto, não é possível marcar menos que 1.
- Eu posso pensar em um algoritmo simples com pontuação 2 (mas não estou inserindo).
Notas sobre suprema e laços
- Um supremo de um conjunto de números é o menor número que não é menor que qualquer um deles. Isso é muito parecido com o máximo de um conjunto, exceto que alguns conjuntos infinitos como {2/3, 3/4, 4/5, 5/6, ...} não têm um único elemento máximo, mas ainda terão um supremo, neste caso 1.
- Se você conseguir "salvar" apenas um número constante de atribuições no meu algoritmo de pontuação 2 (digamos), sua pontuação ainda será 2, porque você ficará arbitrariamente perto de 2 quanto maior for a sua entrada. No entanto, você ganha no tie-break, se for o caso.
code-challenge
Ben Millwood
fonte
fonte
little-omega(1)
espaço, colocando-o na pilha.O(1)
espaço adicional. Você precisa deO(log n)
espaço para armazenar uma posição de índice, uma vez que um número inteiro de k bits só pode armazenar nelas para cadeias de caracteres de comprimento até2^k
. Limitar o comprimento das strings torna o desafio bastante inútil, pois todo algoritmo exigiriaO(1)
espaço dessa maneira.Respostas:
Python, Pontuação:
21.51.25Esta é a combinação direta entre a resposta do primo e a minha resposta. Então, créditos para ele também!
A prova ainda está em andamento, mas aqui está o código para brincar! Se você encontrar um exemplo contrário de pontuação maior que 1,25 (ou se houver um erro), avise-me!
Atualmente, o pior caso é:
onde há exatamente n de cada uma das letras "a", "b", "c" e "" (espaço) e exatamente dois "d" s. O comprimento da sequência é 4n + 2 e o número de atribuições é 5n + 2 , resultando em uma pontuação de 5/4 = 1,25 .
O algoritmo funciona em duas etapas:
k
tais questring[k]
estring[n-1-k]
sejam limites de palavrasstring[:k]+string[n-1-k:]
(concatenação do primeirok
e do últimok
caracteres) com pequenas modificações.Onde
n
é o comprimento da string.O aprimoramento que esse algoritmo fornece vem da "pequena modificação" na Etapa 2. É basicamente o conhecimento de que na sequência concatenada, os caracteres na posição
k
ek+1
são os limites das palavras (o que significa que são espaços ou o primeiro / último caractere de uma palavra), e, portanto, podemos substituir diretamente os caracteres na posiçãok
ek+1
pelo caractere correspondente na sequência final, economizando algumas atribuições. Isso remove o pior caso do algoritmo de reversão de palavras do hostHá casos em que não podemos realmente encontrar isso
k
; nesse caso, apenas executamos o "algoritmo de reversão de qualquer palavra" em toda a cadeia.O código é longo para lidar com esses quatro casos ao executar o algoritmo de reversão de palavras na cadeia "concatenada":
k
não é encontrado (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
)Tenho certeza de que o código pode ser reduzido. Atualmente, é longo, porque eu não tinha uma imagem clara de todo o algoritmo no começo. Tenho certeza de que se pode projetá-lo para ser representado em um código mais curto =)
Exemplo de execução (primeiro é meu, segundo é primo):
Você pode ver que a pontuação é quase a mesma, exceto no pior caso do algoritmo de reversão de palavras do host no terceiro exemplo, para o qual minha abordagem gera pontuação menor que 1,25
Python, Pontuação: 1.5
O número exato de atribuições pode ser aproximado pela fórmula:
sendo o pior caso:
com 55 atribuições em sequência com comprimento 37.
A idéia é semelhante à anterior, mas nesta versão tentei encontrar prefixo e sufixo nos limites das palavras com diferença de comprimento no máximo 1. Então, eu executo meu algoritmo anterior nesse prefixo e sufixo (imagine-os como sendo concatenados) . Depois continue na parte não processada.
Por exemplo, para o pior caso anterior:
primeiro faremos a reversão de palavras em "ab" e "c" (4 atribuições) para ser:
Sabemos que no limite costumava ser espaço (há muitos casos a serem tratados, mas você pode fazer isso), portanto, não precisamos codificar o espaço no limite, esse é o principal aprimoramento do algoritmo anterior .
Finalmente, rodamos nos quatro caracteres do meio para obter:
no total, 8 tarefas, o ideal para este caso, pois todos os 8 caracteres foram alterados.
Isso elimina o pior caso do algoritmo anterior, pois o pior caso do algoritmo anterior é eliminado.
Veja alguns exemplos de execução (e comparação com a resposta do @ primo - esta é a segunda linha):
A resposta do primo é geralmente melhor, embora em alguns casos eu possa ter 1 ponto de vantagem =)
Também o código dele é muito mais curto que o meu, haha.
Python, Score: assintoticamente 2, no caso normal, muito menos
código antigo removido devido a restrição de espaço
A idéia é iterar através de cada índice e, para cada índice
i
, pegamos o caractere, calculamos a nova posiçãoj
, memorizamos o caractere na posiçãoj
, atribuímos o caracterei
aj
e repetimos com o caractere no índicej
. Como precisamos das informações de espaço para calcular a nova posição, codifico o espaço antigo como a versão em maiúscula da nova letra e o novo espaço como '@'.fonte
length(string)/3
forçando cada palavra na pior das hipóteses a ter pelo menos 2 de alguma forma), a pontuação será menor que 2 (no exemplo acima, será 1,67)if any(process_loop(...) for j in range(...))
atribuições desses loops de processo não precisariam ser contadas?dry_run
parâmetro está definido como diferente de zero (o valor parai
). Dentro deprocess_loop
, sedry_run
for diferente de zero, ele não fará nenhuma atribuição.Perl, pontuação 1.3̅
Para cada caractere não espacial, é realizada uma atribuição e, para cada caractere espacial, duas atribuições.
Como os caracteres espaciais não podem representar mais da metade do número total de caracteres, a pior pontuação é 1,5 .O algoritmo não mudou, mas posso provar um limite superior inferior. Vamos fazer duas observações:
Pode-se então ver que o 'pior caso' teórico com espaços assintoticamente 1/2 não é o pior caso:
ab c d e f g h i ...
De fato, é um bom caso.
Para impedir a observação um e dois acima, cada palavra de um caractere precisaria ser reposicionada no meio de uma palavra com três ou mais caracteres. Isso sugeriria o pior caso que contenha assintoticamente 1/3 de espaço:
a bcd a bcd a ... bc
Ou, equivalentemente, apenas palavras de dois caracteres:
a bc de fg hi jk ...
Como o pior caso contém 1/3 de espaços assintoticamente, o pior caso se torna 1,3̅ .
Edit: Adicionado um contador de swap e a proporção.
A entrada é retirada do stdin. Uso da amostra:
Método
Para começar, o primeiro caractere da sequência é movido para seu destino final. O caractere recém-substituído é então movido para seu destino, etc. Isso continua até que uma das duas condições seja atendida:
Quando isso ocorre, o personagem não é trocado pelo espaço, mas pela posição de espelho do espaço. O algoritmo continua a partir dessa posição.
Quando o alvo retorna à posição inicial inicial do ciclo atual, é necessário encontrar o próximo caractere não trocado (ou melhor, qualquer caractere não trocado). Para fazer isso sob constantes restrições de memória, todos os swaps feitos até esse momento são rastreados.
Após esta fase, cada caractere não espacial foi movido no máximo uma vez. Para finalizar, todos os caracteres de espaço são trocados pelos caracteres em suas posições de espelho, exigindo duas operações de atribuição por espaço.
fonte
Ruby, pontuação 2
Como iniciante, um algoritmo muito básico. Primeiro, ela reverte toda a sequência e depois reverte cada palavra na sequência novamente. Na pior das hipóteses (uma palavra, número par de caracteres), a pontuação passa a 2.
Uso:
fonte
C ++: Pontuação 2
fonte
Rebol
Não estou claro a pontuação para isso. Não há atribuição direta de string neste código. Tudo é tratado por aquele
reverse/part
que inverte in-loco e inicialmente no conjunto a cadeia.Alguns detalhes no código:
Passe pela string (
series
) até atingir otail?
Na primeira vez em loop, faça o reverso completo da string -
reverse/part series tail series
(que é igual areverse series
)Em seguida, inverta todas as palavras encontradas em outras iterações -
reverse/part series find series space
Quando a palavra esgotada encontrar, retorne
tail series
para que ela inverta a última palavra na string -reverse/part series tail series
Rebol permite atravessar uma corda através de um ponteiro interno . Você pode ver isso em
series: next f
(mova o ponteiro para depois do espaço, iniciando a próxima palavra) eseries: head series
(redefine o ponteiro de volta à cabeça).Veja Série para mais informações.
Exemplo de uso no console Rebol:
fonte
C: Pontuação 2
Isso apenas inverte a string inteira uma vez e depois inverte cada palavra.
fonte
Python: pontuação 2
Quase idêntico ao algoritmo de Howard, mas executa as etapas de reversão ao contrário (primeiro inverte as palavras e depois inverte toda a cadeia). Usada memória adicional é de 3 variáveis byte-size:
i
,j
, et
. Tecnicamente,find
elen
estão usando algumas variáveis internas, mas elas podem ser reutilizadas com a mesma facilidadei
ouj
sem perda de função.edição rápida: economizando em atribuições de string trocando apenas quando os caracteres diferem, para que eu consiga alguns pontos extras da nota 2.
fonte
Lote
Admito que não entendi completamente a pontuação (acho que são duas) .. mas vou dizer - faz a coisa .
A entrada é tomado como primeiro valor da entrada padrão, e por isso precisa ser colocado entre aspas -
chamada:
script.bat "hello there everyone"
out:
everyone there hello
.Talvez alguém possa me pontuar (supondo que eu não tenha me desqualificado de alguma outra maneira).
fonte
Javascript
Uso:
Tenho a estranha sensação de que perdi algo ...
fonte