Subarray Máximo e Subarray de Produto Máximo
Aplique o algoritmo de Kadane a maximum-sum-subarray e estenda-o para acompanhar os valores máximo e mínimo na variante de produto.
Subarray Máximo e Subarray de Produto Máximo é uma aula grátis de DSA Interview Prep no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de DSA Interview Prep, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de DSA Interview Prep inclui 4 aulas no total.
Problema do subvetor de soma máxima
O problema do subvetor de soma máxima solicita que você encontre o subvetor contíguo dentro de um vetor unidimensional de números que tenha a maior soma. Por exemplo, em [-2, 1, -3, 4, -1, 2, 1, -5, 4], o subvetor [4, -1, 2, 1] fornece a soma máxima de 6. Uma abordagem de força bruta O(n²) verifica todos os subvetores, mas o algoritmo de Kadane resolve o problema em O(n).
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
# Brute force: O(n^2)
max_sum = float('-inf')
for i in range(len(nums)):
curr = 0
for j in range(i, len(nums)):
curr += nums[j]
max_sum = max(max_sum, curr)
print(max_sum) # 6Intuição do algoritmo de Kadane
O algoritmo de Kadane percorre o vetor uma vez, mantendo uma current_sum acumulada. Para cada elemento, você decide: é melhor estender o subvetor existente ou começar novamente a partir deste elemento? Se current_sum se torna negativa, isso apenas prejudicaria qualquer subvetor futuro, então reinicie. A recorrência é current_sum = max(num, current_sum + num).
def max_subarray(nums):
max_sum = current_sum = nums[0]
for num in nums[1:]:
# Extend or start fresh?
current_sum = max(num, current_sum + num)
max_sum = max(max_sum, current_sum)
return max_sum
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
print(max_subarray(nums)) # 6Acompanhando o algoritmo de Kadane
Vamos acompanhar o algoritmo de Kadane em [-2, 1, -3, 4, -1, 2, 1, -5, 4]: começamos com a soma atual igual a -2 e o máximo igual a -2. Em 1: soma atual=max(1,-2+1)=1, máximo=1. Em -3: soma atual=max(-3,1-3)=-2, máximo=1. Em 4: soma atual=max(4,-2+4)=4, máximo=4. Em -1: soma atual=3, máximo=4. Em 2: soma atual=5, máximo=5. Em 1: soma atual=6, máximo=6. Em -5: soma atual=1. Em 4: soma atual=5, máximo=6. O algoritmo identifica corretamente o subvetor que termina no índice 6 como o ideal.
def max_subarray_trace(nums):
curr = max_sum = nums[0]
for i, num in enumerate(nums[1:], 1):
new_curr = max(num, curr + num)
max_sum = max(max_sum, new_curr)
print(f'i={i}, num={num}, curr: {curr}->{new_curr}, max={max_sum}')
curr = new_curr
return max_sum
max_subarray_trace([-2, 1, -3, 4, -1, 2, 1, -5, 4])Retornando o subvetor propriamente dito
Se o entrevistador solicitar que você retorne o próprio subvetor (não apenas a soma), será necessário acompanhar os índices inicial e final. Ao reiniciar (porque num > current_sum + num), atualize um temp_start. Ao atualizar max_sum, salve temp_start como start e o índice atual como end. Isso acrescenta uma sobrecarga O(1) ao mesmo algoritmo O(n).
def max_subarray_indices(nums):
max_sum = curr = nums[0]
start = end = temp_start = 0
for i in range(1, len(nums)):
if nums[i] > curr + nums[i]:
curr = nums[i]
temp_start = i
else:
curr += nums[i]
if curr > max_sum:
max_sum = curr
start, end = temp_start, i
return max_sum, nums[start:end+1]
print(max_subarray_indices([-2, 1, -3, 4, -1, 2, 1, -5, 4]))
# (6, [4, -1, 2, 1])Problema do subvetor de produto máximo
O problema do subvetor de produto máximo é mais complexo que a variante da soma por causa dos números negativos. Dois números negativos, quando multiplicados, resultam em um número positivo; assim, um produto muito negativo pode se tornar o máximo depois de ser multiplicado por outro número negativo. Para [2, 3, -2, 4], a resposta é 6 ([2, 3]). Para [-2, 0, -1], a resposta é 0. Precisamos acompanhar os produtos máximo e mínimo a cada etapa.
nums = [2, 3, -2, 4]
# [2,3,-2,4]: products [2, 6, -12, -48]
# subarrays: [2]=2, [2,3]=6, [3]=3, etc.
# max is 6 from subarray [2,3]
nums2 = [-2, 3, -4]
# [-2]*3*[-4] = 24
# negative*negative=positive!
print('Expected:', 24)Acompanhando os produtos máximo e mínimo
A principal ideia é: em cada posição, o produto máximo atual é um de num, max_so_far * num ou min_so_far * num (este último ajuda quando um número negativo transforma o mínimo em máximo). O mesmo vale para o mínimo. Atualize ambos cur_max e cur_min simultaneamente usando os valores anteriores para evitar usar valores já atualizados na mesma etapa.
def max_product(nums):
max_prod = min_prod = result = nums[0]
for num in nums[1:]:
# All three candidates for new max
candidates = (num, max_prod * num, min_prod * num)
max_prod, min_prod = max(candidates), min(candidates)
result = max(result, max_prod)
return result
print(max_product([2, 3, -2, 4])) # 6
print(max_product([-2, 3, -4])) # 24
print(max_product([-2, 0, -1])) # 0
print(max_product([-2])) # -2Por que min_prod é importante
Considere [-3, -10, 5]. Depois de processar -3: máximo=-3, mínimo=-3. Depois de -10: os candidatos são (-10, 30, 30) → máximo=30, mínimo=-10. Depois de 5: os candidatos são (5, 150, -50) → máximo=150. Sem acompanhar min_prod, você perderia a inversão que ocorre quando um mínimo muito negativo é multiplicado por outro número negativo. Calcule sempre max e min a partir dos mesmos valores anteriores para evitar um erro de leitura de valor desatualizado.
def max_product_traced(nums):
max_p = min_p = result = nums[0]
for num in nums[1:]:
prev_max, prev_min = max_p, min_p
max_p = max(num, prev_max * num, prev_min * num)
min_p = min(num, prev_max * num, prev_min * num)
result = max(result, max_p)
print(f'num={num}: max_p={max_p}, min_p={min_p}')
return result
max_product_traced([-3, -10, 5])
# max_p after -10: 30 (flip!)
# max_p after 5: 150Zeros reiniciam o produto
Um zero no vetor reinicia ambos os produtos acumulados para zero, dividindo efetivamente o vetor em subvetores independentes. Quando num = 0, tanto max_prod * 0 = 0 quanto min_prod * 0 = 0, portanto os três candidatos se tornam 0, e o resultado máximo anterior é preservado. Não é necessário nenhum código para casos especiais — a fórmula geral trata os zeros naturalmente.
def max_product(nums):
max_p = min_p = result = nums[0]
for num in nums[1:]:
cands = (num, max_p * num, min_p * num)
max_p, min_p = max(cands), min(cands)
result = max(result, max_p)
return result
# Zero splits array into independent subarrays
print(max_product([3, -1, 4, 0, 2, 5, -1])) # 10 (2*5)
print(max_product([0, 2])) # 2
print(max_product([-1, 0, -2])) # 0Alternativa: varredura do produto da esquerda para a direita
Uma abordagem alternativa percorre o vetor da esquerda para a direita e da direita para a esquerda, redefinindo o produto acumulado para 1 ao encontrar zero. O subvetor de produto máximo nunca atravessa um zero; portanto, se um número negativo piorar o resultado em uma direção, a varredura inversa capturará a inversão. Essa abordagem é elegante, mas o método de acompanhamento de mínimo/máximo é mais comumente esperado em entrevistas.
def max_product_sweep(nums):
result = max(nums)
left = right = 1
n = len(nums)
for i in range(n):
left *= nums[i]
right *= nums[n - 1 - i]
result = max(result, left, right)
if left == 0: left = 1
if right == 0: right = 1
return result
print(max_product_sweep([2, 3, -2, 4])) # 6
print(max_product_sweep([-2, 3, -4])) # 24
print(max_product_sweep([-2, 0, -1])) # 0Kadane versus produto: principais diferenças
Os subvetores de soma e de produto diferem de maneiras importantes. Para a soma, números negativos são sempre prejudiciais, então você reinicia de forma gananciosa. Para o produto, dois números negativos ajudam, portanto é necessário acompanhar os dois extremos. Além disso, os zeros encerram os produtos, mas são apenas levemente prejudiciais para as somas. Ao explicar a solução em entrevistas, reconheça explicitamente essas diferenças e explique por que é necessário acompanhar o mínimo antes de escrever qualquer código.
# Max Sum Subarray: O(n) time, O(1) space
def max_sum(nums):
curr = result = nums[0]
for n in nums[1:]:
curr = max(n, curr + n) # restart or extend
result = max(result, curr)
return result
# Max Product Subarray: O(n) time, O(1) space
def max_prod(nums):
lo = hi = result = nums[0]
for n in nums[1:]:
lo, hi = min(n, lo*n, hi*n), max(n, lo*n, hi*n)
result = max(result, hi)
return result
print(max_sum([-2, 1, -3, 4, -1, 2, 1])) # 6
print(max_prod([-2, 3, -4])) # 24Complexidade e dicas para entrevistas
Tanto o algoritmo de Kadane (soma máxima) quanto o acompanhamento de mínimo/máximo (produto máximo) são executados em tempo O(n) e usam espaço O(1). Dicas importantes para entrevistas: (1) Para a soma máxima, mencione a alternativa de Divisão e Conquista O(n log n) para demonstrar amplitude. (2) Para o produto máximo, enfatize que você atualiza min_prod e max_prod simultaneamente a partir dos valores anteriores para evitar usar dados desatualizados. (3) Sempre esclareça: o vetor pode estar vazio? O subvetor precisa ser não vazio? (Sim, por convenção, ele precisa ser não vazio.)
# Both run O(n) time, O(1) space
# Kadane handles: all negative (returns least negative)
# Product handles: zeros (resets naturally), negatives (tracks both extremes)
nums_all_neg = [-5, -2, -8]
print('Max sum (all neg):', max(max(nums_all_neg[0:1]),
max(x for x in nums_all_neg))) # -2
# Correct: return the maximum element when all are negativeVerificação rápida
Teste sua compreensão dos conceitos de Estruturas de Dados e Algoritmos — Preparação para Entrevistas de Programação desta lição.
Recapitulação da lição
Nesta lição, você aprendeu: o algoritmo de Kadane resolve o subvetor de soma máxima em O(n), escolhendo estendê-lo ou reiniciá-lo em cada elemento, o subvetor de produto máximo exige acompanhar os produtos acumulados mínimo e máximo devido às inversões causadas por números negativos e os zeros reiniciam naturalmente o produto acumulado, sem código para casos especiais. Em seguida, exploraremos o problema de segmentação de palavras usando uma tabela DP unidimensional.
Perguntas Frequentes
A aula “Subarray Máximo e Subarray de Produto Máximo” é grátis?
Sim — o texto completo de “Subarray Máximo e Subarray de Produto Máximo” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de DSA Interview Prep, atualize para CoddyKit PRO. O curso de DSA Interview Prep inclui 4 aulas no total.
O que vou aprender em “Subarray Máximo e Subarray de Produto Máximo”?
Aplique o algoritmo de Kadane a maximum-sum-subarray e estenda-o para acompanhar os valores máximo e mínimo na variante de produto. Você pratica DSA Interview Prep com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar DSA Interview Prep?
Nenhuma experiência prévia é necessária. DSA Interview Prep no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “Subarray Máximo e Subarray de Produto Máximo”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de DSA Interview Prep?
Sim. Cada aula de DSA Interview Prep inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- House Robber: Recorrência Escolher ou Ignorar
- Subarray Máximo e Subarray de Produto Máximo
- Quebra de Palavras e Segmentação de Strings
- Decodificando Formas e Contando Caminhos