Pular para o conteudo principal

Como pensar em complexidade de tempo e espaço

Complexidade é um jeito simples de comparar custo quando a entrada cresce.

Andrews Ribeiro

Andrews Ribeiro

Founder & Engineer

O problema

Muita gente ouve Big O e entra em modo defesa.

Ou tenta decorar uma tabela.

Ou começa a falar de matemática como se isso, por si só, resolvesse o problema.

O travamento acontece porque complexidade costuma ser ensinada como notação antes de ser ensinada como ferramenta.

Só que, em entrevista e no trabalho real, o ponto não é recitar símbolo.

O ponto é responder perguntas como:

  • essa solução escala melhor ou pior que a outra?
  • o custo cresce por causa de quê?
  • estou trocando memória por velocidade?
  • esse custo faz sentido para a entrada que eu tenho?

Modelo mental

Complexidade é uma forma compacta de descrever como o custo cresce quando a entrada cresce.

Só isso.

Tempo fala de trabalho executado.

Espaço fala de memória extra necessária para a solução funcionar.

Se quiser um resumo mais humano:

Complexidade não mede se o código é bonito. Mede quanto ele sofre quando o tamanho do problema aumenta.

O erro comum é imaginar que complexidade descreve o programa inteiro com perfeição absoluta.

Ela não descreve tudo.

Ela destaca o que domina o crescimento.

Quebrando o problema

Primeiro encontre a operação dominante

Você não precisa analisar cada linha com obsessão.

Procure o que mais se repete ou o que mais pesa no crescimento.

Exemplos:

  • um loop simples sobre n elementos tende a virar O(n)
  • dois loops aninhados sobre n tendem a virar O(n²)
  • dividir o problema ao meio repetidamente costuma apontar para O(log n)

Quase sempre a pergunta útil é:

O que mais cresce aqui quando a entrada aumenta?

Descreva em palavras antes da notação

Se você tenta pular direto para o símbolo, costuma travar mais.

Melhor fazer assim:

  1. diga o que a solução faz
  2. diga quantas vezes a parte cara roda
  3. só então traduza para a notação

Exemplo:

“Eu percorro o array uma vez e faço uma consulta no Hash Map a cada passo. Então o custo cresce linearmente com a entrada. Isso fica O(n) no caso médio.”

Esse raciocínio costuma soar muito mais forte do que só soltar o símbolo.

Ignore o que não muda o jogo

Em análise de crescimento, constantes e detalhes menores normalmente perdem importância.

2n, 3n e n + 10 continuam crescendo linearmente.

Isso não quer dizer que constante nunca importa.

Importa, sim, quando a escala é pequena ou quando a operação constante é muito pesada.

Mas para comparar estrutura de solução, o formato do crescimento geralmente importa mais do que o enfeite.

Separe tempo de espaço

Uma solução pode ser ótima de tempo e cara de memória.

Outra pode economizar memória e cobrar mais CPU.

Esse tipo de troca aparece o tempo todo.

É por isso que vale nomear sempre os dois lados:

  • tempo: quantas operações crescem com a entrada
  • espaço auxiliar: quanta memória extra a solução aloca além dos dados de entrada

Nem todo O(1) é mágico

Esse é um tropeço frequente em entrevista.

A pessoa fala que acesso em Hash Map é O(1) e para por aí.

O jeito melhor de falar é:

“No caso médio, Hash Map me dá acesso muito rápido. No pior caso, depende de colisões e da implementação.”

Isso mostra maturidade sem transformar a resposta em aula acadêmica.

Exemplo simples

Imagine o problema:

Dado um array, diga se existe valor duplicado.

Solução 1

Comparar cada posição com todas as outras.

Você faz um loop externo e, para cada item, varre o resto.

Isso cresce como O(n²).

Espaço extra: praticamente O(1).

Solução 2

Percorrer uma vez usando Set.

Para cada número:

  • se já está no Set, existe duplicado
  • se não está, adiciona e continua

Agora o custo de tempo fica O(n) no caso médio.

Espaço extra: O(n), porque você guarda o que já viu.

Esse exemplo já mostra o raciocínio que o entrevistador quer ver:

  • primeiro identifique o gargalo
  • depois proponha a troca
  • por fim explique o preço pago

Erros comuns

  • Falar a notação sem explicar o porquê.
  • Misturar tamanho de código com complexidade de execução.
  • Ignorar espaço auxiliar e falar só de tempo.
  • Tratar Hash Map como O(1) absoluto sem nenhuma nuance.
  • Tentar parecer sofisticado antes de mostrar a baseline mais simples.

Como um senior pensa

Quem tem mais experiência normalmente usa complexidade como linguagem de decisão, não como exercício de quadro branco.

O raciocínio costuma ser:

  • qual é a baseline mais simples?
  • onde está o gargalo?
  • vale pagar memória para reduzir tempo?
  • o tamanho da entrada realmente justifica otimização?

Isso importa porque nem toda melhora assintótica compensa a complexidade de implementação.

O(n) é melhor que O(n²).

Mas uma solução mais complexa também tem custo de manutenção, bug e tempo de explicação.

Senioridade aqui é saber comparar os custos certos para o contexto certo.

O que o entrevistador quer ver

Ele não está procurando alguém que decorou uma lista de símbolos.

Está procurando alguém que:

  • identifica a parte dominante da solução
  • consegue comparar duas abordagens com clareza
  • sabe falar de tempo e espaço sem confundir os dois
  • usa complexidade para justificar escolha, não para posar de teórico

Se você conseguir dizer “essa solução percorre a entrada uma vez, usa memória extra para evitar trabalho repetido e por isso cai de O(n²) para O(n)”, já está mostrando quase tudo que interessa.

Complexidade boa é a que ajuda a decidir. Não a que só soa técnica.

Em entrevista, clareza de comparação costuma valer mais do que notação despejada sem contexto.

Resumo rápido

O que vale manter na cabeça

Checklist de pratica

Use isto ao responder

Você concluiu este artigo

Próximo artigo Como fazer take-home com bom escopo Artigo anterior Enquadrar o problema antes de codificar

Continue explorando

Artigos relacionados