← Back to home

Two Sum

By Pscodium · 8/4/2026 · 3 views

Two Sum — Encontrando Dois Números que Somam um Valor

O Two Sum é um dos problemas mais conhecidos do LeetCode.

Ele é um problema simples de entender, mas muito importante para aprender conceitos fundamentais de algoritmos e estruturas de dados.

O problema ajuda a entender:

  • Arrays
  • Loops
  • Hash Maps
  • Complexidade de algoritmos
  • Otimização de código

A pergunta é:

Dado um array de números e um valor alvo, encontre dois números cuja soma seja igual ao valor alvo.


1. O problema

Imagine que temos:

numbers = [2, 7, 11, 15]

target = 9

Precisamos encontrar dois números que somados resultem em 9.

Podemos observar:

2 + 7 = 9

Portanto, a resposta é:

[0, 1]

Porque:

numbers[0] = 2
numbers[1] = 7

O resultado esperado são os índices dos números, e não os números em si.


2. Outro exemplo

Imagine:

numbers = [3, 2, 4]

target = 6

Precisamos encontrar:

2 + 4 = 6

Os índices são:

2 → índice 1

4 → índice 2

Portanto:

[1, 2]

3. A solução mais simples

Uma primeira solução seria comparar todos os números entre si.

Por exemplo:

function twoSum(numbers: number[], target: number): number[] {
  for (let i = 0; i < numbers.length; i++) {
    for (let j = i + 1; j < numbers.length; j++) {
      if (numbers[i] + numbers[j] === target) {
        return [i, j];
      }
    }
  }

  return [];
}

Podemos testar:

const result = twoSum([2, 7, 11, 15], 9);

console.log(result);

Resultado:

[0, 1]

4. Como essa solução funciona?

Temos dois loops.

O primeiro seleciona um número:

2

O segundo compara com os próximos:

2 + 7 = 9

Encontramos a resposta.

Se não encontrar:

2 + 11
2 + 15

Passamos para o próximo:

7 + 11
7 + 15

E assim por diante.

O problema é que precisamos testar muitas combinações.


5. Complexidade

Para um array com n elementos, podemos acabar fazendo aproximadamente:

n × n

comparações.

Portanto:

Time Complexity: O(n²)

Por exemplo:

10 elementos
→ aproximadamente 100 comparações

1.000 elementos
→ aproximadamente 1.000.000 comparações

1.000.000 elementos
→ aproximadamente 1.000.000.000.000 comparações

Isso pode ficar muito lento.

Precisamos encontrar uma solução melhor.


6. A ideia do HashMap

A pergunta principal é:

Se eu tenho um número, qual número preciso encontrar para chegar ao target?

Imagine:

number = 2

target = 9

Precisamos de:

9 - 2 = 7

Ou seja:

2 + 7 = 9

Então, para cada número, calculamos:

complement = target - number

Depois verificamos se esse complemento já apareceu.


7. Usando um HashMap

Em JavaScript e TypeScript, podemos usar um Map.

A ideia é armazenar:

número → índice

Por exemplo:

2 → 0
7 → 1
11 → 2
15 → 3

Assim conseguimos verificar rapidamente se um número já foi encontrado.


8. Solução otimizada

function twoSum(numbers: number[], target: number): number[] {
  const map = new Map<number, number>();

  for (let i = 0; i < numbers.length; i++) {
    const current = numbers[i];
    const complement = target - current;

    if (map.has(complement)) {
      return [map.get(complement)!, i];
    }

    map.set(current, i);
  }

  return [];
}

Vamos entender passo a passo.


9. Primeiro elemento

Temos:

numbers = [2, 7, 11, 15]

target = 9

Começamos com:

Map = {}

Primeiro número:

current = 2

Calculamos:

complement = 9 - 2

Resultado:

complement = 7

Perguntamos:

O número 7 já apareceu?

Ainda não.

Então armazenamos:

Map

2 → 0

10. Segundo elemento

Agora:

current = 7

Calculamos:

complement = 9 - 7

Resultado:

complement = 2

Perguntamos:

O número 2 já apareceu?

Sim.

Temos:

2 → índice 0

E estamos no:

7 → índice 1

Então retornamos:

[0, 1]

Resultado:

2 + 7 = 9

11. Visualizando o algoritmo

Podemos pensar assim:

Array:

[2, 7, 11, 15]

Primeiro:

2
│
├── Target = 9
│
└── Preciso de 7

O 7 ainda não existe no Map.

Então:

Map

2 → 0

Agora:

7
│
├── Target = 9
│
└── Preciso de 2

O 2 existe:

2 → 0

Encontramos:

[0, 1]

12. Complexidade otimizada

A solução com Map percorre o array apenas uma vez.

Portanto:

Time Complexity: O(n)

O Map utiliza memória adicional:

Space Complexity: O(n)

Temos então:

Solução simples:

Tempo: O(n²)
Memória: O(1)


Solução com HashMap:

Tempo: O(n)
Memória: O(n)

Trocamos memória por velocidade.

Esse é um dos trade-offs mais comuns em algoritmos.


13. Um exemplo prático: sistema de pagamentos

Imagine que você está desenvolvendo um sistema de pagamentos.

Você possui uma lista de valores disponíveis:

[10, 20, 50, 100, 200]

E precisa encontrar duas transações que juntas formem um determinado valor.

Por exemplo:

target = 70

Podemos encontrar:

20 + 50 = 70

Usando:

const transactions = [10, 20, 50, 100, 200];

const result = twoSum(transactions, 70);

console.log(result);

Resultado:

[1, 2]

Porque:

transactions[1] = 20
transactions[2] = 50

Então:

20 + 50 = 70

14. Um exemplo ainda mais realista

Imagine um sistema de e-commerce que precisa encontrar dois produtos cujo preço combinado seja exatamente o valor de um cupom.

Temos:

const products = [
  29.90,
  49.90,
  79.90,
  99.90,
  149.90
];

const couponValue = 129.80;

Precisamos encontrar dois produtos:

29.90 + 99.90 = 129.80

Uma implementação poderia ser:

function findProductsForCoupon(
  prices: number[],
  couponValue: number
): number[] {
  const map = new Map<number, number>();

  for (let i = 0; i < prices.length; i++) {
    const price = prices[i];
    const needed = couponValue - price;

    if (map.has(needed)) {
      return [map.get(needed)!, i];
    }

    map.set(price, i);
  }

  return [];
}

Uso:

const products = [
  29.90,
  49.90,
  79.90,
  99.90,
  149.90
];

const result = findProductsForCoupon(
  products,
  129.80
);

console.log(result);

Resultado:

[0, 3]

Ou seja:

Produto 0 → R$ 29,90

Produto 3 → R$ 99,90

Total:

R$ 29,90 + R$ 99,90 = R$ 129,80

Em um sistema real, provavelmente usaríamos valores inteiros em centavos para evitar problemas de precisão com números decimais:

const productsInCents = [
  2990,
  4990,
  7990,
  9990,
  14990
];

const couponValue = 12980;

Agora:

2990 + 9990 = 12980

Isso evita problemas comuns de ponto flutuante.


15. O conceito por trás do Two Sum

O mais importante nesse problema não é apenas encontrar dois números.

É aprender a fazer a pergunta:

"O que eu preciso encontrar para completar o valor que tenho?"

Se:

target = 10

E encontramos:

current = 3

Então:

needed = 10 - 3

Precisamos encontrar:

7

Se encontramos:

current = 8

Precisamos de:

2

A lógica é:

             TARGET
                │
                ▼
        TARGET - CURRENT
                │
                ▼
            NEEDED

Depois verificamos se NEEDED já foi encontrado.


16. E se existirem números negativos?

A solução continua funcionando.

Por exemplo:

numbers = [-3, 4, 7, 2]

target = 1

Temos:

-3 + 4 = 1

A solução encontra:

[-3, 4]

Porque:

1 - (-3) = 4

O Map não se importa se os valores são:

  • Positivos
  • Negativos
  • Zero

17. E se o número aparecer duas vezes?

Por exemplo:

numbers = [3, 3]

target = 6

Precisamos de:

3 + 3 = 6

O algoritmo funciona:

Primeiro 3
    │
    ▼
Map = { 3 → 0 }

Segundo 3
    │
    ▼
Preciso de 3
    │
    ▼
3 já existe

Resultado:

[0, 1]

18. O padrão "Complement"

O padrão utilizado no Two Sum é extremamente importante.

Podemos resumir:

for each item:

    needed = target - current

    if needed exists:
        found

    else:
        store current

Esse padrão aparece em muitos problemas envolvendo:

  • Soma
  • Diferença
  • Frequência
  • Busca de pares
  • Duplicatas

E normalmente envolve:

HashMap

ou:

HashSet

19. Two Sum vs força bruta

A diferença principal:

Força Bruta

Para cada número
    Para cada outro número
        Testar combinação

Complexidade:

O(n²)

HashMap

Para cada número
    Calcular complemento
    Procurar no Map

Complexidade:

O(n)

A grande mudança foi deixar de procurar:

"Qualquer par possível?"

e passar a perguntar:

"Qual número exatamente eu preciso?"

Essa mudança de pensamento é uma das principais lições do problema.


Conclusão

O Two Sum consiste em encontrar dois números dentro de um array cuja soma seja igual a um valor alvo.

Por exemplo:

numbers = [2, 7, 11, 15]

target = 9

A resposta é:

2 + 7 = 9

E os índices:

[0, 1]

A solução mais simples utiliza dois loops:

O(n²)

Mas podemos otimizar utilizando um Map:

O(n)

A ideia central é calcular o complemento:

needed = target - current

E verificar se ele já foi encontrado.

A solução final fica:

function twoSum(numbers: number[], target: number): number[] {
  const map = new Map<number, number>();

  for (let i = 0; i < numbers.length; i++) {
    const needed = target - numbers[i];

    if (map.has(needed)) {
      return [map.get(needed)!, i];
    }

    map.set(numbers[i], i);
  }

  return [];
}

A grande lição do Two Sum é:

Quando você precisa encontrar dois valores que juntos satisfazem uma condição, pense no complemento que falta e use uma estrutura de dados eficiente para encontrá-lo rapidamente.

Esse padrão de pensamento é muito mais importante do que o próprio problema e aparece frequentemente em entrevistas técnicas e em outros problemas de algoritmos.


Comments

No comments yet.