Pular para o conteudo principal

Melhor hora para comprar e vender ação

Como sair da comparação de todos os pares e perceber que o problema só pede o menor preco até agora.

Dado um array prices, onde prices[i] e o preco de uma ação no dia i, retorne o lucro máximo que você pode obter comprando em um dia e vendendo em um dia posterior.

Se nenhum lucro for possível, retorne 0.

Exemplo:

Input:  prices = [7, 1, 5, 3, 6, 4]
Output: 5

Compre no preco 1 e venda no preco 6.

O que perceber antes de codar

Erros comuns

Passo 1 — Ler a restrição mais importante

O lucro e venda - compra.

Mas nem toda combinação vale.

A compra precisa acontecer antes da venda.

Isso elimina uma leitura errada bem comum: pegar o menor preco do array inteiro e o maior preco do array inteiro sem respeitar a ordem.

Passo 2 — Escrever a versão inicial correta

A primeira versão certa compara cada dia de compra com todos os dias de venda depois dele:

export function maxProfit(prices: number[]): number {
  let bestProfit = 0

  for (let buyDay = 0; buyDay < prices.length; buyDay += 1) {
    for (let sellDay = buyDay + 1; sellDay < prices.length; sellDay += 1) {
      bestProfit = Math.max(bestProfit, prices[sellDay] - prices[buyDay])
    }
  }

  return bestProfit
}

Funciona. Mas percorre o resto do array de novo para cada dia.

Passo 3 — Perguntar o que o dia atual precisa saber

Quando você chega no preco de hoje, precisa lembrar de todos os dias anteriores?

Não.

Para calcular o melhor lucro vendendo hoje, só importa uma coisa:

qual foi o menor preco que eu vi até agora?

Se você souber isso, o lucro candidato do dia vira:

lucro = precoAtual - menorPrecoAteAgora

Passo 4 — Atualizar duas informações durante uma passada O(n)

Durante uma unica passada:

  • mantenha o menor preco visto até agora
  • calcule o lucro candidato de hoje
  • atualize o melhor lucro encontrado

O problema inteiro cabe nisso.

O editor interativo precisa de JavaScript. Voce ainda pode ler o desafio e copiar o codigo inicial abaixo.

Codigo inicial

export function maxProfit(prices: number[]): number {
  // sua solução aqui
  return 0
}
solution.ts
Travado? Dicas disponiveis.

Ainda não resolveu?

Ver a solução agora pode reduzir o aprendizado. Vale a pena tentar mais um pouco.

Abrir a solucao de referencia

Sem JavaScript, a solucao de referencia aparece inline em vez de um dialogo.

Solução

Complexidade final

Tempo: O(n)

Espaço: O(1)

Solução 1 — Força bruta O(n²)

Compare cada dia de compra com todos os dias de venda depois dele.

export function maxProfit(prices: number[]): number {
  let bestProfit = 0

  for (let buyDay = 0; buyDay < prices.length; buyDay += 1) {
    for (let sellDay = buyDay + 1; sellDay < prices.length; sellDay += 1) {
      bestProfit = Math.max(bestProfit, prices[sellDay] - prices[buyDay])
    }
  }

  return bestProfit
}

Correta, mas lenta porque repete comparações demais.

Solução 2 — Passada unica O(n)

Se o dia atual só precisa do menor preco já visto, guarde só isso.

export function maxProfit(prices: number[]): number {
  let minPrice = Infinity
  let bestProfit = 0

  for (const price of prices) {
    minPrice = Math.min(minPrice, price)
    bestProfit = Math.max(bestProfit, price - minPrice)
  }

  return bestProfit
}

Você anda uma vez pelo array e mantem exatamente as duas informações que importam.

O que dizer na entrevista

Uma explicação curta e boa seria:

A versão inicial compara cada compra com cada venda posterior e custa O(n²). Mas, para cada dia, eu não preciso lembrar de todos os precos anteriores. Eu só preciso do menor preco até agora. Com isso, calculo o lucro candidato em O(1) por dia e resolvo em uma passada.

Isso mostra que você:

  • respeitou a restrição de ordem
  • identificou a informação mínima necessária
  • justificou a otimização sem pular etapas

Quando esse padrão aparece de novo

Esse padrão reaparece quando você precisa:

  • manter um melhor valor visto até agora
  • atualizar resposta enquanto percorre
  • decidir com base em estado acumulado simples
  • evitar estrutura extra quando duas variaveis bastam

O ponto não e decorar esse problema.

O ponto e perceber quando a entrada pode ser resolvida com memória acumulada durante a passada.

Proximo desafio Subarray máximo Desafio anterior Parênteses válidos

Desafios relacionados

Artigos relacionados