Sous-tableau de somme maximale et sous-tableau de produit maximal
Appliquez l’algorithme de Kadane à maximum-sum-subarray et étendez-le pour suivre à la fois les valeurs maximale et minimale dans la variante du produit.
Sous-tableau de somme maximale et sous-tableau de produit maximal est une leçon DSA Interview Prep gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage DSA Interview Prep, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours DSA Interview Prep comprend 4 leçons au total.
Problème du sous-tableau de somme maximale
Le problème du sous-tableau de somme maximale vous demande de trouver, dans un tableau unidimensionnel de nombres, le sous-tableau contigu dont la somme est la plus grande. Par exemple, dans [-2, 1, -3, 4, -1, 2, 1, -5, 4], le sous-tableau [4, -1, 2, 1] donne la somme maximale, soit 6. Une approche par force brute en O(n²) vérifie tous les sous-tableaux, mais l'algorithme de Kadane résout ce problème en 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) # 6Intuition derrière l'algorithme de Kadane
L'algorithme de Kadane parcourt le tableau une seule fois en maintenant une current_sum cumulative. À chaque élément, vous devez décider s'il vaut mieux étendre le sous-tableau existant ou recommencer à partir de cet élément. Si current_sum devient négative, elle ne ferait que nuire à tout sous-tableau futur : il faut donc recommencer. La récurrence est 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)) # 6Parcours de l'algorithme de Kadane
Suivons l'algorithme de Kadane sur [-2, 1, -3, 4, -1, 2, 1, -5, 4] : au départ, la somme courante vaut -2 et le maximum vaut -2. Pour 1, la somme courante devient 1 et le maximum vaut 1. Pour -3, la somme courante devient -2 et le maximum reste 1. Pour 4, la somme courante devient 4 et le maximum vaut 4. Pour -1, la somme courante vaut 3 et le maximum reste 4. Pour 2, la somme courante vaut 5 et le maximum devient 5. Pour 1, la somme courante vaut 6 et le maximum devient 6. Pour -5, la somme courante vaut 1. Pour 4, elle vaut 5 et le maximum reste 6. L'algorithme identifie correctement le sous-tableau se terminant à l'indice 6 comme étant optimal.
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])Renvoyer le sous-tableau réel
Si l'intervieweur vous demande de renvoyer le sous-tableau lui-même (et pas seulement la somme), vous devez suivre les indices de début et de fin. Lorsque vous recommencez (car num > current_sum + num), mettez à jour un temp_start. Lorsque vous mettez à jour max_sum, enregistrez temp_start comme start et l'indice courant comme end. Cela ajoute un surcoût de O(1) au même algorithme en 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])Problème du sous-tableau de produit maximal
Le problème du sous-tableau de produit maximal est plus délicat que sa variante fondée sur la somme à cause des nombres négatifs. Deux nombres négatifs donnent un produit positif : un produit très négatif peut donc devenir le maximum après une nouvelle multiplication par un nombre négatif. Pour [2, 3, -2, 4], le résultat est 6 ([2, 3]). Pour [-2, 0, -1], le résultat est 0. Nous devons suivre à chaque étape les produits maximum et minimum.
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)Suivre les produits maximum et minimum
L'idée clé est la suivante : à chaque position, le produit maximal courant est l'une des valeurs num, max_so_far * num ou min_so_far * num (cette dernière aide lorsqu'un nombre négatif transforme le minimum en maximum). Il en va de même pour le minimum. Mettez à jour simultanément cur_max et cur_min à partir des valeurs précédentes afin de ne pas utiliser, au cours de la même étape, des valeurs déjà mises à jour.
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])) # -2Pourquoi min_prod est important
Considérez [-3, -10, 5]. Après le traitement de -3 : maximum = -3, minimum = -3. Après -10 : les candidats sont (-10, 30, 30) → maximum = 30, minimum = -10. Après 5 : les candidats sont (5, 150, -50) → maximum = 150. Sans suivre min_prod, vous manqueriez l'inversion qui se produit lorsqu'un minimum très négatif est multiplié par un autre nombre négatif. Calculez toujours max et min à partir des mêmes valeurs précédentes afin d'éviter un problème de lecture de valeurs obsolètes.
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: 150Les zéros réinitialisent le produit
Un zéro dans le tableau réinitialise les deux produits cumulés à zéro, ce qui sépare effectivement le tableau en sous-tableaux indépendants. Lorsque num = 0, max_prod * 0 = 0 et min_prod * 0 = 0 : les trois candidats deviennent donc 0, et le maximum du résultat précédent est conservé. Aucun traitement particulier n'est nécessaire : la formule générale gère naturellement les zéros.
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])) # 0Alternative : parcours du produit de gauche à droite et de droite à gauche
Une autre approche effectue un parcours de gauche à droite, puis de droite à gauche, en réinitialisant le produit cumulé à 1 lorsqu'il rencontre un zéro. Le sous-tableau de produit maximal ne traverse jamais un zéro ; ainsi, si un nombre négatif dégrade le résultat dans une direction, le parcours inverse détectera l'inversion. Cette approche est élégante, mais la méthode de suivi du minimum et du maximum est plus souvent attendue lors des entretiens.
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 et produit : différences clés
Les sous-tableaux fondés sur une somme et ceux fondés sur un produit diffèrent de manière importante. Pour la somme, les nombres négatifs sont toujours nuisibles : vous recommencez donc de manière gloutonne. Pour le produit, deux nombres négatifs sont avantageux : vous devez donc suivre les deux extrêmes. De plus, les zéros sont terminaux pour les produits, mais seulement légèrement nuisibles pour les sommes. Lors d'un entretien, reconnaissez explicitement ces différences et expliquez pourquoi il est nécessaire de suivre le minimum avant d'écrire du code.
# 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])) # 24Complexité et conseils pour les entretiens
L'algorithme de Kadane (somme maximale) et le suivi du minimum et du maximum (produit maximal) s'exécutent tous deux en temps O(n) et utilisent un espace O(1). Conseils importants pour les entretiens : (1) Pour la somme maximale, mentionnez l'alternative « diviser pour régner » en O(n log n) afin de montrer l'étendue de vos connaissances. (2) Pour le produit maximal, insistez sur le fait que vous mettez à jour min_prod et max_prod simultanément à partir des valeurs précédentes, afin de ne pas utiliser de données obsolètes. (3) Clarifiez toujours les points suivants : le tableau peut-il être vide ? Le sous-tableau doit-il être non vide ? (Oui, par convention, il doit être non vide.)
# 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 negativeVérification rapide
Évaluez votre compréhension des concepts de structures de données et d'algorithmes — préparation aux entretiens de programmation présentés dans cette leçon.
Récapitulatif de la leçon
Dans cette leçon, vous avez appris : l'algorithme de Kadane résout le problème du sous-tableau de somme maximale en O(n) en choisissant, pour chaque élément, de prolonger le sous-tableau ou de recommencer, le sous-tableau de produit maximal nécessite de suivre simultanément les produits cumulés minimum et maximum en raison des inversions causées par les nombres négatifs, et les zéros réinitialisent naturellement le produit cumulé sans traitement particulier. Ensuite, nous étudierons le problème de la segmentation de mots à l'aide d'une table de DP à une dimension.
Questions Fréquemment Posées
La leçon « Sous-tableau de somme maximale et sous-tableau de produit maximal » est-elle gratuite ?
Oui — le texte complet de « Sous-tableau de somme maximale et sous-tableau de produit maximal » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours DSA Interview Prep, passe à CoddyKit PRO. Le cours DSA Interview Prep comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Sous-tableau de somme maximale et sous-tableau de produit maximal » ?
Appliquez l’algorithme de Kadane à maximum-sum-subarray et étendez-le pour suivre à la fois les valeurs maximale et minimale dans la variante du produit. Tu pratiques DSA Interview Prep avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer DSA Interview Prep ?
Aucune expérience préalable n'est requise. DSA Interview Prep sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.
Combien de temps prend la leçon « Sous-tableau de somme maximale et sous-tableau de produit maximal » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon DSA Interview Prep ?
Oui. Chaque leçon DSA Interview Prep inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- House Robber : récurrence prendre ou ignorer
- Sous-tableau de somme maximale et sous-tableau de produit maximal
- Word Break et segmentation de chaînes
- Décoder des façons et compter des chemins