voltar aos artigosadvanced topics
$cd~/artigos/algorithms-big-o-javascript-complexidade-performance
Advanced Topics
série 33 Conceitos JS·parte 36 de 38

Algorithms & Big O: A Ciência da Performance

22 minVanderlei José Alamino

"A diferença entre um bom programador e um excelente programador não é quanto código ele escreve — é quanto código ele evita escrevendo escolhendo o algoritmo certo."

Big O descreve como tempo ou espaço crescem quando o input aumenta — não velocidade absoluta em segundos, mas taxa de crescimento.

snippetJavaScript
// O(n²) — loops aninhadosfor (let i = 0; i < n; i++)  for (let j = 0; j < n; j++) { /* ... */ } // O(log n) — busca bináriawhile (left <= right) { mid = ...; /* elimina metade */ }

Neste guia da série 33 Conceitos JS — projeto open source criado por Leonardo Maldonado — você aprende a analisar código, escolher algoritmos e aplicar padrões de entrevista.

Pré-requisitos: Data Structures, Recursion e Map, Reduce & Filter.

algorithms-big-o-javascript-complexidade-performance.meta.jsonjson

// metadados do artigo

{
  "tag": "advanced topics",
  "readTime": "22 min",
  "author": "Vanderlei José Alamino",
  "source": "33jsconcepts.com",
  "series": "33 Conceitos JS",
  "part": {
    "current": 36,
    "total": 38
  }
}
abrir fonte original
algorithms-big-o-javascript-complexidade-performance.mdmarkdown

Fonte de referência

Conteúdo adaptado a partir do guia original em inglês.

33jsconcepts.com
01

seção

Analogia: Entrega de Pacotes

snippettext
O(1)   → endereço exato — mesmo tempo com 10 ou 10.000 casasO(n)   → checa cada casa — dobra input, dobra tempoO(n²)  → compara cada par — 100 casas = 10.000 comparações

Big O mede escalabilidade e pior caso — ignora constantes (O(2n) → O(n)).

02

seção

O que Big O Mede (e Não Mede)

Mede: taxa de crescimento, pior caso, comparação entre algoritmos.

Não mede: ms reais, hardware, memória exata (isso é space complexity).

Regra de ouro: O(n) com 1ms/elem pode perder para O(n²) em n pequeno — mas n grande, O(n) sempre vence.

03

seção

A Escala de Complexidade

Big ONomeExemplo1M itens (ordem)
O(1)Constantearr[i], Map.get1 op
O(log n)LogarítmicaBusca binária~20 ops
O(n)Linearloop simples~1M ops
O(n log n)Linearítmicasort()~20M ops
O(n²)Quadráticaloops aninhados~1T ops
snippetJavaScript
arr[2];           // O(1)map.get('key');   // O(1)arr.push(6);      // O(1)arr.indexOf(5);  // O(n)[...arr].sort(); // O(n log n)

log₂(1.000.000) ≈ 20 — busca binária escala muito bem.

04

seção

Como Analisar Seu Código

  1. Identifique n (ex.: arr.length)
  2. Conte loops — aninhados multiplicam
  3. Descarte constantes e termos menores
snippetJavaScript
function example(arr) {  console.log(arr[0]);              // O(1)  for (const x of arr) { }          // O(n)  for (let i = 0; i < arr.length; i++)    for (let j = 0; j < arr.length; j++) { }  // O(n²)}// Total: O(n²) — termo dominante

Loop interno com 10 iterações fixas → O(n × 10) = O(n).

05

seção

Complexidade Built-in do JavaScript

MétodoBig O
push, popO(1)
shift, unshiftO(n)
indexOf, includes, findO(n)
map, filter, forEachO(n)
sort()O(n log n) — TimSort no V8

Set.has() O(1) vs Array.includes() O(n) — para múltiplas buscas, converta para Set.

06

seção

Algoritmos de Busca

Linear — O(n):

snippetJavaScript
function linearSearch(arr, target) {  for (let i = 0; i < arr.length; i++)    if (arr[i] === target) return i;  return -1;}

Binária — O(log n) — requer array ordenado:

snippetJavaScript
function binarySearch(arr, target) {  let left = 0, right = arr.length - 1;  while (left <= right) {    const mid = Math.floor((left + right) / 2);    if (arr[mid] === target) return mid;    if (arr[mid] < target) left = mid + 1;    else right = mid - 1;  }  return -1;}

Muitas buscas? Ordene uma vez O(n log n) + binárias O(log n) cada.

07

seção

Algoritmos de Ordenação

AlgoritmoPiorEspaçoUso
Bubble sortO(n²)O(1)Só ensino
Merge sortO(n log n)O(n)Garantido
Quick sortO(n²)*O(log n)Geral
JS sort()O(n log n)O(n)Produção
snippetJavaScript
function bubbleSort(arr) {  const r = [...arr];  for (let i = 0; i < r.length; i++) {    let swapped = false;    for (let j = 0; j < r.length - i - 1; j++) {      if (r[j] > r[j + 1]) {        [r[j], r[j + 1]] = [r[j + 1], r[j]];        swapped = true;      }    }    if (!swapped) break;  }  return r;}

Na prática: [...arr].sort((a, b) => a - b) — implemente merge sort para aprender, não para prod.

08

seção

Two Pointers — O(n)

Dois índices em array ordenado — par que soma target:

snippetJavaScript
function twoSumSorted(arr, target) {  let left = 0, right = arr.length - 1;  while (left < right) {    const sum = arr[left] + arr[right];    if (sum === target) return [left, right];    if (sum < target) left++;    else right--;  }  return null;}

Soma pequena → move left (valor maior). Soma grande → move right.

09

seção

Sliding Window — O(n)

Janela deslizante — soma máxima de k consecutivos:

snippetJavaScript
function maxSumSubarray(arr, k) {  let windowSum = arr.slice(0, k).reduce((a, b) => a + b, 0);  let maxSum = windowSum;  for (let i = k; i < arr.length; i++) {    windowSum = windowSum - arr[i - k] + arr[i];    maxSum = Math.max(maxSum, windowSum);  }  return maxSum;}

Recalcular do zero seria O(n × k); slide é O(n).

Substring única mais longa também usa sliding window + Set.

10

seção

Frequency Counter — O(n)

Contagem com Map/Object evita O(n²):

snippetJavaScript
function isAnagram(a, b) {  if (a.length !== b.length) return false;  const freq = {};  for (const c of a) freq[c] = (freq[c] || 0) + 1;  for (const c of b) {    if (!freq[c]) return false;    freq[c]--;  }  return true;}

Duplicatas em O(n):

snippetJavaScript
function hasDuplicates(arr) {  const seen = new Set();  for (const item of arr)    if (seen.has(item)) return true;    else seen.add(item);  return false;}
11

seção

Tempo vs Espaço

Set/Map para O(1) lookup → O(n) espaço extra.

Loops aninhados → O(n²) tempo, O(1) espaço extra.

Escolha o trade-off certo para o tamanho do input e memória disponível.

12

seção

Perguntas Clássicas de Entrevista

13

seção

Teste Seu Conhecimento

$ summary --quick

Resumo rápido

  • Big O — taxa de crescimento, não ms absolutos
  • O(1), O(log n) rápidos; O(n) ok; O(n²) evite em escala
  • Loops aninhados multiplicam — n × n = O(n²)
  • Descarte constantes — O(10n) → O(n)
  • push/pop O(1); shift/unshift O(n)
  • Set.has O(1) vs includes O(n) em buscas repetidas
  • Binária O(log n) — dados ordenados obrigatórios
  • sort() nativo — O(n log n) em produção
  • Padrões — two pointers, sliding window, frequency counter
  • Espaço importa — Set/Map trocam memória por tempo

Créditos da série

Este artigo faz parte de uma série de estudos inspirada no projeto 33 Conceitos JS, criado por Leonardo Maldonado. Todo o conteúdo original está disponível em 33jsconcepts.com.