Algoritmos na prática
Dois usos da mesma base: consertar código que fica lento quando os dados crescem, e
treinar a resolução de problemas.
A ideia que manda aqui: análise é hipótese, medição é evidência. Ler o código e dizer "isso
é O(n²)" é um palpite bem informado; dobrar o tamanho da entrada e ver o tempo quadruplicar é a
prova. E o contrário também vale: saber o n real decide se vale mexer. O gateway.ts do
Trindade tem o comentário certo: "Com cinco pessoas e talvez quinze conexões, percorrer o mapa
inteiro num broadcast custa nada — não invente índice por canal antes de precisar." Saber o custo,
saber o n e decidir não otimizar é uso maduro de Big-O.
A base (leia a parte que a situação pedir)
| Nota |
Para quê |
A:\Claude\02-cerebro\70-aprendizado\10-fundamentos\complexidade-big-o.md |
Como estimar lendo código, o custo dos métodos embutidos de JS e Python, e como medir (seções 7 e 8) |
...\10-fundamentos\estruturas-de-dados.md |
Tabela de custos e "qual escolher, na prática" em JS e Python |
...\10-fundamentos\paradigmas-de-algoritmo.md |
Os padrões (dois ponteiros, janela, prefix sum, hash) e a tabela "sinais no enunciado" |
...\10-fundamentos\ordenacao-e-busca.md · arvores-e-grafos.md |
Quando o problema é ordenar, buscar, caminho ou dependência |
...\60-carreira-e-comunidade\entrevista-tecnica.md |
O método de 6 passos e a ordem de tópicos para treino |
(... = A:\Claude\02-cerebro\70-aprendizado.)
Modo A — código real está lento
1. Confirmar que o problema é de crescimento
Pergunte: fica mais lento conforme os dados crescem? Se uma requisição é lenta com poucos
dados, o gargalo provavelmente é rede, disco, banco ou renderização, e esta skill não é a
ferramenta: diga isso e aponte a certa. Descubra o n real (quantos itens, usuários, arquivos,
mensagens), hoje e no pior caso plausível.
Separe as dimensões limitadas das que crescem com o tempo. Procure o limite no próprio código:
validação (z.array(...).max(6)), constante compartilhada, tamanho do grupo. Dimensão limitada por
regra dá custo constante, por mais aninhado que o laço pareça. A que pesa é a que acumula
sem teto: histórico, mensagens, registros de uma consulta sem limit. No teste real desta skill
(13/09/2026, enquetes do Trindade), opções (≤ 6) e pessoas (5) eram limitadas; o número de
enquetes de um canal não era, e era ele que tornava a listagem quadrática.
2. Medir antes
Isole a função suspeita e rode com dados sintéticos em pelo menos três tamanhos dobrando
(n, 2n, 4n). A razão entre os tempos dá a classe:
| Dobrou n e o tempo… |
Classe provável |
| ficou igual |
O(1) ou O(log n) |
| dobrou |
O(n) |
| pouco mais que dobrou |
O(n log n) |
| quadruplicou |
O(n²) |
Node: use a mediana de 5 execuções com performance.now() (o modelo está na seção 8 de
complexidade-big-o.md). Python: timeit. Sem saber onde está o gasto, perfile primeiro:
node --cpu-prof arquivo.js gera um .cpuprofile que o DevTools do Chrome abre, e
python -m cProfile -s cumtime script.py lista as funções pelo tempo acumulado.
3. Ler e estimar
Regras: passos em sequência somam (fica o maior); laços aninhados multiplicam; laço que
corta pela metade é log; recursão se analisa desenhando a árvore de chamadas; método
embutido não é grátis. Nomeie as variáveis de verdade: laço sobre usuários dentro de laço
sobre mensagens é O(u·m), não "O(n²)".
4. Caçar os sinais
| Sinal no código |
Por que custa |
Troca típica |
includes/indexOf/find/some dentro de laço (JS) · x in lista dentro de laço (Py) |
cada consulta percorre a lista: O(n·m) |
montar um Set/Map (set/dict) uma vez antes do laço |
filter dentro de map |
O(a·b) |
agrupar numa passada com Map (ou Map.groupBy, presente no Node 24) |
[...acc, x], concat ou {...obj} dentro de reduce/laço |
copia tudo a cada item: O(n²) |
acumulador local mutado com push ou atribuição |
shift()/unshift() (JS) · pop(0)/insert(0, x) (Py) |
move todos os outros: O(n) cada |
índice de cabeça · collections.deque |
sort dentro de laço, ou ordenar só para pegar o menor |
O(n log n) repetido |
uma passada, ou heap (heapq; em JS, heap próprio) |
| recursão que recalcula o mesmo subproblema |
exponencial |
memoização ou tabulação (ver as pegadinhas abaixo) |
| uma consulta ao banco por item (N+1) |
cada passo custa milissegundos, não nanossegundos |
uma consulta em lote + Map para achar cada resultado (padrão de messages.db.ts do Trindade) |
5. Propor a menor mudança que resolve
Diga a complexidade antes e depois e o custo de memória da troca: Set e Map compram tempo
com memória O(n). Não reescreva o módulo: troque a estrutura ou o laço.
6. Provar que o comportamento não mudou
Rode os testes que existirem. Se não houver, escreva uma checagem de equivalência: a função
antiga e a nova recebem os mesmos dados aleatórios e os mesmos casos de borda (vazio, um item,
duplicados, ordem), e as saídas precisam ser iguais. Isso existe porque as trocas desta tabela
mudam semântica em silêncio. Set compara objetos por referência, trata NaN como igual a
NaN e preserva a ordem de inserção. dict e set exigem chave imutável. Agrupar pode mudar a
ordem da saída.
7. Medir depois
Mesmo roteiro, mesmos tamanhos. Entregue a tabela n | antes | depois | razão e a explicação da
razão pela complexidade.
8. Decidir com o n real
Se o n real é pequeno e o ganho não se sente, recomende não mudar e diga por quê. Vale deixar
um comentário no código com o custo e o n, como o gateway.ts faz: vira decisão registrada, não
descuido.
Dois fatores mudam a régua:
- Onde o código roda. Num servidor Node, CPU gasta num laço bloqueia o event loop: enquanto
o
filter roda, nenhuma outra requisição nem mensagem de WebSocket é atendida, de ninguém. Meça
contra esse orçamento (dezenas de milissegundos já atrasam o tempo real de todos), não só contra
a paciência de quem clicou. No navegador, o mesmo vale para a thread de interface.
- Quanto a troca custa. Se a dimensão cresce sem teto, a correção é pequena, local e tem
equivalência provada, dá para recomendar a troca sem urgência, dizendo em que n ela passa a
doer. Se a correção é grande, espere a medição de produção pedir.
Pegadinhas deste modo
- Big-O ignora constantes, e o usuário não. Para n pequeno, meça em vez de supor.
- "O(1)" de hash é média. Hash ruim leva tudo para o mesmo balde.
- Memoização em JS com chave de array não funciona:
memo.get([i, j]) compara referência e
nunca acha. Use `${i},${j}`.
- Recursão com cache ainda estoura a pilha. O Python 3.10 para em 1.000 chamadas por padrão;
tabule de baixo para cima.
- Medir uma vez só. A primeira execução no Node inclui o aquecimento do JIT; use mediana.
Modo B — treinar
- Escolha o tópico. Na ordem do coding-interview-university (complexidade → arrays, listas,
pilha, fila, hash → busca binária → árvores e heap → ordenação → grafos → recursão e
programação dinâmica), ou pelo ponto fraco que aparece no diário de
A:\Claude\02-cerebro\70-aprendizado\90-progresso\progresso-estudos.md.
- Dê um problema pequeno e claro, em JavaScript ou Python, como a pessoa preferir.
- A pessoa conduz os 6 passos; o Claude faz a pergunta de cada um:
- Esclarecer: "qual o tamanho de n? pode ter repetido, negativo, vazio?"
- Exemplos: "monte um normal e dois de borda, e resolva à mão."
- Força bruta: "qual a solução óbvia, e qual a complexidade dela?"
- Otimizar: "que trabalho a força bruta repete? que estrutura ou padrão elimina?" — e a
nova complexidade antes de codar.
- Codar narrando.
- Testar: percorrer à mão com o exemplo, depois as bordas, e repetir tempo e espaço.
- Travou: um degrau por pedido da escada de dicas (pergunta de volta → aponta o conceito →
aponta o lugar → pseudocódigo → trecho com lacuna → solução só com pedido explícito). A escada
completa está em
...\50-construir-do-zero\construir-do-zero-metodo.md.
- Depois de resolver: compare com a tabela "sinais no enunciado" e proponha uma variação
do mesmo problema. Refazer variando prova que entendeu e não decorou.
- Registre uma linha no diário com o script da skill
estudar (revisao.py diario "...") e,
se o treino cobriu as perguntas de revisão de uma nota da trilha, registre a nota também.
Por que resolver durante o estudo, e não depois: o autor do coding-interview-university
aprendeu isso do jeito caro: horas de vídeo e anotação, e meses depois não lembrava. A regra
dele é 2 ou 3 problemas ao terminar cada tópico, e voltar ao tópico mais tarde.
Como saber que funcionou
Modo A — passou se todas são verdade:
- Houve medição antes e depois em pelo menos 3 tamanhos, com a tabela entregue.
- A razão observada foi explicada pela complexidade.
- A checagem de equivalência (ou os testes existentes) passou, incluindo casos de borda.
- Ou então: a recomendação foi não mudar, com o n real e o custo medido como argumento.
Modo B — passou se: a solução foi escrita pela pessoa, a complexidade foi dita antes de
codar, e pelo menos dois casos de borda foram testados rodando.
1---2name: algoritmos-na-pratica3description: Acha e conserta custo algorítmico ruim em código REAL — laço dentro de laço, includes/indexOf/find/filter dentro de laço, shift() ou pop(0) em fila, cópia de array a cada iteração, ordenação repetida, recursão que recalcula, uma consulta ao banco por item (N+1), estrutura de dados errada — MEDINDO antes e depois com tamanhos crescentes e provando que o resultado não mudou. Também treina resolução de problemas de algoritmo com o método de 6 passos e dica graduada, sem entregar a resposta pronta. Use quando disser 'isso tá lento', 'trava com muitos itens', 'demora quando a lista cresce', 'otimiza esse loop', 'qual a complexidade disso', 'Big-O', 'Map ou objeto', 'Set ou array', 'qual estrutura de dados usar', 'quero treinar algoritmo', 'exercício de lógica', 'leetcode'. NÃO use para renderização lenta, rede ou Core Web Vitals (performance-optimization), animação travando (optimize-web-animations) nem consulta SQL lenta por falta de índice (sql-database-assistant).4---56# Algoritmos na prática78Dois usos da mesma base: **consertar** código que fica lento quando os dados crescem, e9**treinar** a resolução de problemas.1011**A ideia que manda aqui: análise é hipótese, medição é evidência.** Ler o código e dizer "isso12é O(n²)" é um palpite bem informado; dobrar o tamanho da entrada e ver o tempo quadruplicar é a13prova. E o contrário também vale: **saber o n real decide se vale mexer.** O `gateway.ts` do14Trindade tem o comentário certo: "Com cinco pessoas e talvez quinze conexões, percorrer o mapa15inteiro num broadcast custa nada — não invente índice por canal antes de precisar." Saber o custo,16saber o n e decidir não otimizar é uso maduro de Big-O.1718---1920## A base (leia a parte que a situação pedir)2122| Nota | Para quê |23|---|---|24| `A:\Claude\02-cerebro\70-aprendizado\10-fundamentos\complexidade-big-o.md` | Como estimar lendo código, o custo dos métodos embutidos de JS e Python, e **como medir** (seções 7 e 8) |25| `...\10-fundamentos\estruturas-de-dados.md` | Tabela de custos e "qual escolher, na prática" em JS e Python |26| `...\10-fundamentos\paradigmas-de-algoritmo.md` | Os padrões (dois ponteiros, janela, prefix sum, hash) e a tabela "sinais no enunciado" |27| `...\10-fundamentos\ordenacao-e-busca.md` · `arvores-e-grafos.md` | Quando o problema é ordenar, buscar, caminho ou dependência |28| `...\60-carreira-e-comunidade\entrevista-tecnica.md` | O método de 6 passos e a ordem de tópicos para treino |2930(`...` = `A:\Claude\02-cerebro\70-aprendizado`.)3132---3334## Modo A — código real está lento3536### 1. Confirmar que o problema é de crescimento3738Pergunte: **fica mais lento conforme os dados crescem?** Se uma requisição é lenta com poucos39dados, o gargalo provavelmente é rede, disco, banco ou renderização, e esta skill não é a40ferramenta: diga isso e aponte a certa. Descubra o **n real** (quantos itens, usuários, arquivos,41mensagens), hoje e no pior caso plausível.4243**Separe as dimensões limitadas das que crescem com o tempo.** Procure o limite no próprio código:44validação (`z.array(...).max(6)`), constante compartilhada, tamanho do grupo. Dimensão limitada por45regra dá custo **constante**, por mais aninhado que o laço pareça. A que pesa é a que **acumula46sem teto**: histórico, mensagens, registros de uma consulta sem `limit`. No teste real desta skill47(13/09/2026, enquetes do Trindade), opções (≤ 6) e pessoas (5) eram limitadas; o número de48enquetes de um canal não era, e era ele que tornava a listagem quadrática.4950### 2. Medir antes5152Isole a função suspeita e rode com dados sintéticos em **pelo menos três tamanhos dobrando**53(n, 2n, 4n). A razão entre os tempos dá a classe:5455| Dobrou n e o tempo… | Classe provável |56|---|---|57| ficou igual | O(1) ou O(log n) |58| dobrou | O(n) |59| pouco mais que dobrou | O(n log n) |60| quadruplicou | O(n²) |6162Node: use a mediana de 5 execuções com `performance.now()` (o modelo está na seção 8 de63`complexidade-big-o.md`). Python: `timeit`. Sem saber onde está o gasto, perfile primeiro:64`node --cpu-prof arquivo.js` gera um `.cpuprofile` que o DevTools do Chrome abre, e65`python -m cProfile -s cumtime script.py` lista as funções pelo tempo acumulado.6667### 3. Ler e estimar6869Regras: passos em sequência **somam** (fica o maior); laços aninhados **multiplicam**; laço que70corta pela metade é **log**; recursão se analisa desenhando a árvore de chamadas; **método71embutido não é grátis**. Nomeie as variáveis de verdade: laço sobre usuários dentro de laço72sobre mensagens é O(u·m), não "O(n²)".7374### 4. Caçar os sinais7576| Sinal no código | Por que custa | Troca típica |77|---|---|---|78| `includes`/`indexOf`/`find`/`some` dentro de laço (JS) · `x in lista` dentro de laço (Py) | cada consulta percorre a lista: O(n·m) | montar um `Set`/`Map` (`set`/`dict`) **uma vez** antes do laço |79| `filter` dentro de `map` | O(a·b) | agrupar numa passada com `Map` (ou `Map.groupBy`, presente no Node 24) |80| `[...acc, x]`, `concat` ou `{...obj}` dentro de `reduce`/laço | copia tudo a cada item: O(n²) | acumulador local mutado com `push` ou atribuição |81| `shift()`/`unshift()` (JS) · `pop(0)`/`insert(0, x)` (Py) | move todos os outros: O(n) cada | índice de cabeça · `collections.deque` |82| `sort` dentro de laço, ou ordenar só para pegar o menor | O(n log n) repetido | uma passada, ou heap (`heapq`; em JS, heap próprio) |83| recursão que recalcula o mesmo subproblema | exponencial | memoização ou tabulação (ver as pegadinhas abaixo) |84| uma consulta ao banco por item (N+1) | cada passo custa milissegundos, não nanossegundos | uma consulta em lote + `Map` para achar cada resultado (padrão de `messages.db.ts` do Trindade) |8586### 5. Propor a menor mudança que resolve8788Diga a complexidade **antes e depois** e o custo de memória da troca: `Set` e `Map` compram tempo89com memória O(n). Não reescreva o módulo: troque a estrutura ou o laço.9091### 6. Provar que o comportamento não mudou9293Rode os testes que existirem. Se não houver, escreva uma **checagem de equivalência**: a função94antiga e a nova recebem os mesmos dados aleatórios e os mesmos casos de borda (vazio, um item,95duplicados, ordem), e as saídas precisam ser iguais. Isso existe porque as trocas desta tabela96mudam semântica em silêncio. `Set` compara objetos por **referência**, trata `NaN` como igual a97`NaN` e preserva a ordem de inserção. `dict` e `set` exigem chave imutável. Agrupar pode mudar a98ordem da saída.99100### 7. Medir depois101102Mesmo roteiro, mesmos tamanhos. Entregue a tabela `n | antes | depois | razão` e a explicação da103razão pela complexidade.104105### 8. Decidir com o n real106107Se o n real é pequeno e o ganho não se sente, **recomende não mudar** e diga por quê. Vale deixar108um comentário no código com o custo e o n, como o `gateway.ts` faz: vira decisão registrada, não109descuido.110111Dois fatores mudam a régua:112113- **Onde o código roda.** Num servidor Node, CPU gasta num laço **bloqueia o event loop**: enquanto114 o `filter` roda, nenhuma outra requisição nem mensagem de WebSocket é atendida, de ninguém. Meça115 contra esse orçamento (dezenas de milissegundos já atrasam o tempo real de todos), não só contra116 a paciência de quem clicou. No navegador, o mesmo vale para a thread de interface.117- **Quanto a troca custa.** Se a dimensão cresce sem teto, a correção é pequena, local e tem118 equivalência provada, dá para recomendar a troca **sem urgência**, dizendo em que n ela passa a119 doer. Se a correção é grande, espere a medição de produção pedir.120121### Pegadinhas deste modo122123- **Big-O ignora constantes, e o usuário não.** Para n pequeno, meça em vez de supor.124- **"O(1)" de hash é média.** Hash ruim leva tudo para o mesmo balde.125- **Memoização em JS com chave de array não funciona:** `memo.get([i, j])` compara referência e126 nunca acha. Use `` `${i},${j}` ``.127- **Recursão com cache ainda estoura a pilha.** O Python 3.10 para em 1.000 chamadas por padrão;128 tabule de baixo para cima.129- **Medir uma vez só.** A primeira execução no Node inclui o aquecimento do JIT; use mediana.130131---132133## Modo B — treinar1341351. **Escolha o tópico.** Na ordem do coding-interview-university (complexidade → arrays, listas,136 pilha, fila, hash → busca binária → árvores e heap → ordenação → grafos → recursão e137 programação dinâmica), ou pelo ponto fraco que aparece no diário de138 `A:\Claude\02-cerebro\70-aprendizado\90-progresso\progresso-estudos.md`.1392. **Dê um problema pequeno e claro**, em JavaScript ou Python, como a pessoa preferir.1403. **A pessoa conduz os 6 passos**; o Claude faz a pergunta de cada um:141 1. *Esclarecer:* "qual o tamanho de n? pode ter repetido, negativo, vazio?"142 2. *Exemplos:* "monte um normal e dois de borda, e resolva à mão."143 3. *Força bruta:* "qual a solução óbvia, e qual a complexidade dela?"144 4. *Otimizar:* "que trabalho a força bruta repete? que estrutura ou padrão elimina?" — e a145 nova complexidade **antes** de codar.146 5. *Codar* narrando.147 6. *Testar:* percorrer à mão com o exemplo, depois as bordas, e repetir tempo e espaço.1484. **Travou:** um degrau por pedido da escada de dicas (pergunta de volta → aponta o conceito →149 aponta o lugar → pseudocódigo → trecho com lacuna → solução só com pedido explícito). A escada150 completa está em `...\50-construir-do-zero\construir-do-zero-metodo.md`.1515. **Depois de resolver:** compare com a tabela "sinais no enunciado" e proponha **uma variação**152 do mesmo problema. Refazer variando prova que entendeu e não decorou.1536. **Registre** uma linha no diário com o script da skill `estudar` (`revisao.py diario "..."`) e,154 se o treino cobriu as perguntas de revisão de uma nota da trilha, registre a nota também.155156**Por que resolver durante o estudo, e não depois:** o autor do coding-interview-university157aprendeu isso do jeito caro: horas de vídeo e anotação, e meses depois não lembrava. A regra158dele é 2 ou 3 problemas ao terminar cada tópico, e voltar ao tópico mais tarde.159160---161162## Como saber que funcionou163164**Modo A — passou se todas são verdade:**1651. Houve medição **antes e depois** em pelo menos 3 tamanhos, com a tabela entregue.1662. A razão observada foi explicada pela complexidade.1673. A checagem de equivalência (ou os testes existentes) passou, incluindo casos de borda.1684. Ou então: a recomendação foi **não mudar**, com o n real e o custo medido como argumento.169170**Modo B — passou se:** a solução foi escrita pela pessoa, a complexidade foi dita antes de171codar, e pelo menos dois casos de borda foram testados rodando.