Escreva um programa (ou função) que exiba quatro complexidades comuns de tempo grande, dependendo de como é executado. De qualquer forma, ele recebe um número inteiro positivo N, que você pode assumir que seja menor que 2 31 .
Quando o programa é executado em sua forma original , ele deve ter complexidade constante . Ou seja, a complexidade deve ser Θ (1) ou, equivalentemente, Θ (1 ^ N) .
Quando o programa é revertido e executado, ele deve ter complexidade linear . Ou seja, a complexidade deve ser Θ (N) ou, equivalentemente, Θ (N ^ 1) .
(Isso faz sentido, poisN^1
é1^N
revertido.)Quando o programa é duplicada , isto é concatenado a si mesma, e executá-lo deverá ter exponencial complexidade, especificamente 2 N . Ou seja, a complexidade deve ser Θ (2 ^ N) .
(Isso faz sentido, pois o2
in2^N
é o dobro do1
in1^N
.)Quando o programa é dobrado e invertida e executá-lo deverá ter polinomial complexidade, especificamente N 2 . Ou seja, a complexidade deve ser Θ (N ^ 2) .
(Isso faz sentido, poisN^2
é2^N
revertido.)
Esses quatro casos são os únicos com os quais você precisa lidar.
Observe que, para maior precisão, estou usando a notação teta grande (Θ) em vez de O grande, porque os tempos de execução dos seus programas devem ser limitados acima e abaixo pelas complexidades necessárias. Caso contrário, apenas escrever uma função em O (1) satisfaria todos os quatro pontos. Não é muito importante entender as nuances aqui. Principalmente, se o seu programa estiver executando operações k * f (N) por alguma constante k, é provável que esteja em Θ (f (N)).
Exemplo
Se o programa original fosse
ABCDE
então executá-lo deve levar tempo constante. Ou seja, se a entrada N é 1 ou 2147483647 (2 31 -1) ou qualquer valor intermediário, ela deve terminar aproximadamente na mesma quantidade de tempo.
A versão invertida do programa
EDCBA
deve levar um tempo linear em termos de N. Ou seja, o tempo necessário para terminar deve ser aproximadamente proporcional a N. Portanto, N = 1 leva menos tempo e N = 2147483647 leva mais.
A versão duplicada do programa
ABCDEABCDE
deve ter tempo two-to-the-N em termos de N. Ou seja, o tempo que leva para terminar deve ser aproximadamente proporcional a 2 N . Portanto, se N = 1 termina em cerca de um segundo, N = 60 levaria mais tempo que a idade do universo para terminar. (Não, você não precisa testá-lo.)
A versão duplicada e invertida do programa
EDCBAEDCBA
deve levar um tempo ao quadrado em termos de N. Ou seja, o tempo que leva para terminar deve ser aproximadamente proporcional a N * N. Portanto, se N = 1 termina em cerca de um segundo, N = 60 levaria cerca de uma hora para terminar.
Detalhes
Você precisa mostrar ou argumentar que seus programas estão sendo executados nas complexidades que você diz que são. Fornecer alguns dados de temporização é uma boa ideia, mas também tente explicar por que teoricamente a complexidade está correta.
Tudo bem se, na prática, o tempo gasto pelos seus programas não for perfeitamente representativo de sua complexidade (ou mesmo determinística). por exemplo, a entrada N + 1 às vezes pode ser mais rápida que N.
O ambiente em que você está executando seus programas é importante. Você pode fazer suposições básicas sobre como as linguagens populares nunca perdem tempo intencionalmente em algoritmos, mas, por exemplo, se você conhece sua versão específica do Java implementa a classificação por bolhas em vez de um algoritmo de classificação mais rápido , leve isso em consideração se fizer alguma classificação .
Para todas as complexidades aqui, assuma que estamos falando de cenários de pior caso , não de melhor ou médio.
A complexidade do espaço dos programas não importa, apenas a complexidade do tempo.
Os programas podem produzir qualquer coisa. É importante que eles recebam o número inteiro positivo N e tenham as complexidades de tempo corretas.
Comentários e programas multilinhas são permitidos. (Você pode assumir que o
\r\n
reverso é\r\n
para compatibilidade com o Windows.)
Big O Reminders
Do mais rápido para o mais lento O(1), O(N), O(N^2), O(2^N)
(peça 1, 2, 4, 3 acima).
Termos mais lentos sempre dominam, por exemplo O(2^N + N^2 + N) = O(2^N)
.
O(k*f(N)) = O(f(N))
para constante k. Então O(2) = O(30) = O(1)
e O(2*N) = O(0.1*N) = O(N)
.
Lembre-se O(N^2) != O(N^3)
e O(2^N) != O(3^N)
.
Pontuação
Este é o código normal de golfe. O programa original mais curto (o tempo constante) em bytes vence.
fonte
n = input(); for i in xrange(n): pass
tem complexidade exponencial, porque executa2 ** k
etapas, ondek = log_2(n)
está o tamanho da entrada. Você deve esclarecer se esse é o caso, pois altera drasticamente os requisitos.Respostas:
Python 3 , 102 bytes
Experimente online!
Isso é de O (1 ^ n), pois é isso que o programa faz:
Invertida:
Experimente online!
Isso é de O (n ^ 1), pois é isso que o programa faz:
Dobrado:
Experimente online!
Isso é de O (2 ^ n), pois é isso que o programa faz:
Dobrado e revertido:
Experimente online!
Isso é de O (n ^ 2), pois é isso que o programa faz:
fonte
input()
?k
é a entrada el
é uma, então você ainda está computando1**k
, certo? O que deve levarO(log(k))
tempo, apesar do fato de que você e eu e todo mundo sabemos antecipadamente que é um?Perl 5,
827371 + 1 (para sinalizador -n) = 72 bytesTenho certeza de que posso jogar mais (muito) isso, mas é hora de dormir, passei bastante tempo depurando como está e tenho orgulho do que tenho até agora.
O programa em si não usa a entrada e apenas avalia uma sequência que começa com um comentário e, em seguida, faz uma única substituição de sequência, portanto isso é claramente em tempo constante. É basicamente equivalente a:
Dobrado:
O bit que realmente leva tempo exponencial é o segundo eval: avalia o comando
say for(1..2**$_)
, que lista todos os números de 1 a 2 ^ N, que claramente leva tempo exponencial.Invertida:
Isso (ingenuamente) calcula a soma da entrada, o que claramente leva tempo linear (já que cada adição é em tempo constante). O código que realmente é executado é equivalente a:
A última linha é apenas para que, quando esses comandos forem repetidos, leve tempo quadrático.
Invertida e dobrada:
Isso agora pega o somatório do somatório da entrada (e o adiciona ao somatório da entrada, mas tanto faz). Como ele solicita
N^2
adições, isso leva tempo quadrático. É basicamente equivalente a:A segunda linha encontra a soma da entrada, fazendo
N
adições, enquanto a quarta fazsummation(N)
adições, o que éO(N^2)
.fonte
$x.=q;##say...
vez de$x.=q;#say...
(com dois em#
vez de 1). (Isso explicaria por que você contou 76 bytes em vez de 75). Além disso, você deve contar o-n
sinalizador em seu número de bytes, pois seu programa não faz muito sem ele.eval
oss///
comandos e. Se você fizer oeval
primeiro, precisará apenas desse#
. Boa pegada!#
: produtos$x=~s/#//;
invertidos;//#/s~=x$
, que no seu contexto não fazem nada, como faria com um líder#
. (Eu ainda não testei). Independentemente disso, tenha um +1!Na verdade , 20 bytes
Experimente online!
Entrada:
5
Resultado:
Invertida:
Experimente online!
Resultado:
Dobrado:
Experimente online!
Resultado:
Dobrado e revertido:
Experimente online!
Resultado:
Ideia principal
Na verdade, é uma linguagem baseada em pilha.
abc
é um programa que possui complexidade O (1 n ) e seu duplo possui complexidade O (2 n ).def
é um programa que possui complexidade O (n 1 ) e seu duplo possui complexidade O (n 2 ).Então, minha submissão é
"abc"ƒ"fed"
ondeƒ
é avaliar. Dessa forma,"fed"
não será avaliado.Geração de programa individual
O pseudocódigo do primeiro componente
;(1╖╜ⁿr
:O pseudocódigo do segundo componente
;(1╖╜ⁿ@r
:fonte
Gelatina , 20 bytes
Parcialmente inspirado na solução Leaky Nun's Actually .
As novas linhas iniciais e finais são significativas.
Normal:
Experimente online!
Entrada:
5
Resultado:
Invertida:
Experimente online!
Entrada:
5
Resultado:
Dobrado
Experimente online!
Entrada:
5
Resultado:
Dobrado e invertido
Experimente online!
Entrada:
5
Resultado:
Explicação
A chave aqui está
Ŀ
, o que significa "chama o link no índice n como uma mônada". Os links são indexados de cima para baixo começando em 1, excluindo o link principal (o mais baixo).Ŀ
também é modular; portanto, se você tentar ligar para o número 7 do link 5, na verdade, chamará o link 2.O link chamado neste programa é sempre o do índice 10 (
⁵
), independentemente da versão do programa. No entanto, qual link está no índice 10 depende da versão.O
⁵
que aparece depois de cada umĿ
está lá, para não quebrar quando invertido. O programa irá errar no momento da análise, se não houver um número antesĿ
. Ter um⁵
depois é um nilad fora do lugar, que vai direto para a saída.A versão original chama o link
‘
, que calcula n + 1.A versão reversa chama o link
R
, que gera o intervalo 1 .. n.A versão duplicada chama o link
2*R
, que calcula 2 n e gera o intervalo 1 .. 2 n .A versão dobrada e revertida chama o link
²R
, que calcula n 2 e gera o intervalo 1 .. n 2 .fonte
Befunge-98 , 50 bytes
Normal
Este é de longe o programa mais simples dos 4 - os únicos comandos executados são os seguintes:
Este programa faz algumas coisas irrelevantes antes de pressionar um comando "virar à direita" (
]
) e uma seta. Em seguida, ele atinge 2 comandos "take input". Como existe apenas 1 número na entrada e como o TIO trata&
s, o programa é encerrado após 60 segundos. Se houver 2 entradas (e porque eu posso, sem adicionar bytes), o IP passaria para a função "finalizar programa".Experimente online!
Invertida
Este é um pouco mais complicado. os comandos relevantes são os seguintes:
que é equivalente a
A parte importante aqui é a parte
:. 1-:!k@
. É útil porque, se colocarmos a complexidade correta na pilha antes de executar em uma complexidade de tempo menor, podemos obter a desejada. Isso será usado nos 2 programas restantes dessa maneira.Experimente online!
Dobrado
E o comando relevante são:
Este programa entra em 2 loops. Primeiro, segue o mesmo caminho que o programa normal, que coloca 1 e N na pilha, mas, em vez de passar para o segundo
&
, o IP salta sobre um comentário em um loop que empurra2^N
:Os outros bits da linha 4 são pulados usando
;
sDepois que (2 ^ N) é empurrado para a pilha, movemos uma linha para baixo no loop de impressão mencionado acima. Por causa do primeiro loop, a complexidade do tempo é Θ (N + 2 ^ N), mas isso se reduz a Θ (2 ^ N).
Experimente online!
Dobrado e invertido
Os comandos relevantes:
Isso funciona quase de forma idêntica ao programa invertido, mas
N^2
não é retirado da pilha, porque a primeira linha da segunda cópia do programa é anexada à última linha da primeira, o que significa que o comando drop ($
) nunca é executado , então entramos no loop de impressãoN^2
na parte superior da pilha.Experimente online!
fonte