Pular para o conteudo principal

Subarray máximo

Como perceber que a pergunta certa e se a soma anterior ainda ajuda ou se já esta atrapalhando.

Dado um array de inteiros nums, encontre o subarray contiguo com a maior soma e retorne essa soma.

Exemplo:

Input:  nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
Output: 6

O subarray [4, -1, 2, 1] tem soma 6.

O que perceber antes de codar

Erros comuns

Passo 1 — Entender a palavra que muda tudo

O problema fala em subarray contiguo.

Isso mata uma leitura errada bem comum: escolher numeros espalhados que parecem bons e somar tudo.

Aqui não pode pular.

O trecho precisa ser um bloco seguido.

Passo 2 — Escrever a versão inicial correta

Uma versão inicial boa e testar todos os subarrays possiveis, mas somando de forma incremental:

export function maxSubArray(nums: number[]): number {
  let best = -Infinity

  for (let start = 0; start < nums.length; start += 1) {
    let sum = 0

    for (let end = start; end < nums.length; end += 1) {
      sum += nums[end]
      best = Math.max(best, sum)
    }
  }

  return best
}

Funciona. Mas ainda testa todos os começos contra todos os finais.

Passo 3 — Perguntar o que importa na posição atual

Quando você chega em nums[i], o que quer saber?

Não precisa da melhor soma do array inteiro ainda.

A pergunta local e:

qual e a melhor soma de um subarray que termina exatamente aqui?

E ai entra o ponto central:

  • se a soma anterior ajuda, continue
  • se a soma anterior atrapalha, recomece no valor atual

Passo 4 — Guardar a melhor soma que termina aqui

Isso vira uma recorrencia simples:

bestEndingHere = max(value, bestEndingHere + value)

Depois, compare isso com a melhor resposta global.

Essa e a ideia inteira de Kadane.

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

Codigo inicial

export function maxSubArray(nums: 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 — Testar todos os subarrays O(n²)

Uma versão inicial decente e fixar o início e ir estendendo o fim.

export function maxSubArray(nums: number[]): number {
  let best = -Infinity

  for (let start = 0; start < nums.length; start += 1) {
    let sum = 0

    for (let end = start; end < nums.length; end += 1) {
      sum += nums[end]
      best = Math.max(best, sum)
    }
  }

  return best
}

Correta, mas ainda quadratica.

Solução 2 — Kadane O(n)

Se a pergunta local e “qual a melhor soma que termina aqui?”, uma passada basta.

export function maxSubArray(nums: number[]): number {
  let bestEndingHere = nums[0]
  let bestOverall = nums[0]

  for (let index = 1; index < nums.length; index += 1) {
    const value = nums[index]

    bestEndingHere = Math.max(value, bestEndingHere + value)
    bestOverall = Math.max(bestOverall, bestEndingHere)
  }

  return bestOverall
}

O algoritmo parece curto porque a pergunta foi reduzida para a decisão certa.

O que dizer na entrevista

Uma explicação curta e boa seria:

A versão inicial testa todos os subarrays e custa O(n²). A versão otimizada guarda a melhor soma de subarray que termina na posição atual. Se a soma anterior ajudar, eu continuo. Se atrapalhar, eu recomeco no valor atual. Isso reduz para O(n).

Isso mostra que você:

  • respeitou a restrição de contiguidade
  • transformou o problema global em uma pergunta local
  • explicou Kadane como raciocínio, não como nome decorado

Quando esse padrão aparece de novo

Muita gente descreve Kadane como uma forma de programacao dinamica com estado pequeno.

Em alguns casos, ele também parece guloso, porque a decisão local de continuar ou recomecar e exatamente o que mantem o melhor trecho vivo.

Esse padrão reaparece quando você precisa:

  • decidir entre continuar ou recomecar
  • manter uma melhor resposta local durante a passada
  • transformar programacao dinamica em estado pequeno
  • explicar por que uma escolha local funciona

O ponto não e decorar “Kadane”.

O ponto e perceber quando o estado certo e “melhor resposta terminando aqui”.

Proximo desafio Busca binária Desafio anterior Melhor hora para comprar e vender ação

Desafios relacionados

Artigos relacionados