Sommes préfixes et totaux cumulés
Construisez des tableaux de sommes préfixes pour répondre à des requêtes de sommes sur intervalles en O(1), puis appliquez cette technique à des problèmes de sous-tableaux, comme celui du sous-tableau de somme maximale.
Sommes préfixes et totaux cumulés est une leçon Coding 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 Coding Interview Prep, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Coding Interview Prep comprend 4 leçons au total.
Le problème de la somme sur un intervalle
Étant donné un tableau nums, vous devez répondre à de nombreuses requêtes de la forme suivante : quelle est la somme des éléments de l’indice i à l’indice j ? Calculer chaque requête naïvement prend O(n), si bien que k requêtes coûtent O(n×k). Avec un tableau de sommes préfixes, vous précalculez un total cumulé en O(n), puis répondez à chaque requête en O(1). Il s’agit de l’une des techniques de précalcul les plus utilisées lors des entretiens.
# Naive: O(n) per query
def range_sum_naive(nums, i, j):
return sum(nums[i:j+1])
nums = [1, 3, 5, 7, 9]
print(range_sum_naive(nums, 1, 3)) # 3+5+7 = 15
print(range_sum_naive(nums, 0, 4)) # 1+3+5+7+9 = 25
# For 1000 queries, this takes 5000 operationsConstruire le tableau de sommes préfixes
Définissez prefix[i] comme la somme de nums[0] à nums[i-1] (une case supplémentaire et un décalage d’un indice, avec un tableau indexé à partir de zéro, simplifient les cas limites). Construisez-le en O(n) en un seul parcours : prefix[i] = prefix[i-1] + nums[i-1]. Une requête sur l’intervalle sum(i, j) devient alors prefix[j+1] - prefix[i] : une seule soustraction coûtant O(1).
def build_prefix(nums):
n = len(nums)
prefix = [0] * (n + 1)
for i in range(n):
prefix[i+1] = prefix[i] + nums[i]
return prefix
def range_sum(prefix, i, j):
return prefix[j+1] - prefix[i] # O(1)
nums = [1, 3, 5, 7, 9]
pre = build_prefix(nums)
print(pre) # [0, 1, 4, 9, 16, 25]
print(range_sum(pre, 1, 3)) # 9 - 1 = 8? Wait: 3+5+7=15
# Hmm: prefix[4]-prefix[1] = 16-1 = 15 correct
print(range_sum(pre, 1, 3)) # 15Somme d’un sous-tableau égale à K
Trouver le nombre de sous-tableaux dont la somme est égale à k est un problème classique combinant table de hachage et somme préfixe. L’idée clé est la suivante : la somme du sous-tableau allant de i à j vaut prefix[j] - prefix[i-1]. Si nous voulons qu’elle soit égale à k, alors prefix[i-1] = prefix[j] - k. En parcourant le tableau de gauche à droite tout en maintenant une somme préfixe cumulée, nous recherchons combien de fois current_sum - k est déjà apparu, ce qui permet de compter tous les sous-tableaux valides en O(n) au total.
from collections import defaultdict
def subarray_sum_k(nums, k):
count = 0
current = 0
freq = defaultdict(int)
freq[0] = 1 # empty prefix
for n in nums:
current += n
count += freq[current - k] # how many prior sums give diff=k
freq[current] += 1
return count
print(subarray_sum_k([1, 1, 1], 2)) # 2
print(subarray_sum_k([1, 2, 3], 3)) # 2 ([1,2] and [3])Somme maximale d’un sous-tableau avec une somme préfixe
La somme maximale d’un sous-tableau peut être formulée comme un problème de somme préfixe : pour chaque indice j, nous voulons maximiser prefix[j] - prefix[i] pour tout i < j. À chaque indice j, le i optimal est celui qui correspond à la plus petite somme préfixe observée jusque-là. Un parcours de gauche à droite en mémorisant min_prefix donne une complexité O(n). Cela revient à voir l’algorithme de Kadane sous l’angle des sommes préfixes.
def max_subarray_prefix(nums):
max_sum = float('-inf')
min_pre = 0 # prefix[0] = 0
current = 0
for n in nums:
current += n
max_sum = max(max_sum, current - min_pre)
min_pre = min(min_pre, current)
return max_sum
print(max_subarray_prefix([-2,1,-3,4,-1,2,1,-5,4]))
# 6 (same as Kadane's)
print(max_subarray_prefix([-1,-2,-3]))
# -1Sommes préfixes 2D pour les requêtes sur une grille
Les sommes préfixes s’étendent aux grilles 2D. Définissez P[i][j] comme la somme de tous les éléments du rectangle allant de (0,0) à (i-1,j-1). Construisez-le avec la formule d’inclusion-exclusion : P[i][j] = P[i-1][j] + P[i][j-1] - P[i-1][j-1] + grid[i-1][j-1]. Toute requête de somme du rectangle allant de (r1,c1) à (r2,c2) peut alors être traitée en O(1) à l’aide de quatre consultations.
def build_2d_prefix(grid):
R, C = len(grid), len(grid[0])
P = [[0]*(C+1) for _ in range(R+1)]
for r in range(1, R+1):
for c in range(1, C+1):
P[r][c] = (P[r-1][c] + P[r][c-1]
- P[r-1][c-1] + grid[r-1][c-1])
return P
def rect_sum(P, r1, c1, r2, c2):
return P[r2+1][c2+1] - P[r1][c2+1] - P[r2+1][c1] + P[r1][c1]
grid = [[3,0,1,4],[5,6,3,2],[1,2,0,1]]
P = build_2d_prefix(grid)
print(rect_sum(P, 0, 0, 1, 1)) # 3+0+5+6 = 14Total cumulé pour l’indice d’équilibre
L’indice d’équilibre est la position où la somme des éléments à gauche est égale à la somme des éléments à droite. Précalculez la somme totale, puis parcourez le tableau en maintenant une somme cumulée à gauche. La somme à droite vaut total - left_sum - nums[i]. Vérifiez l’égalité en O(1) pour chaque indice, soit O(n) au total. Cela montre comment un total cumulé peut remplacer deux tableaux de sommes préfixes distincts.
def find_pivot_index(nums):
total = sum(nums)
left_sum = 0
for i, n in enumerate(nums):
# right_sum = total - left_sum - nums[i]
if left_sum == total - left_sum - n:
return i
left_sum += n
return -1
print(find_pivot_index([1, 7, 3, 6, 5, 6])) # 3
print(find_pivot_index([1, 2, 3])) # -1Produit de tous les éléments sauf soi-même
Étant donné un tableau, renvoyez un tableau où chaque élément est le produit de tous les autres. La division est interdite. Utilisez un produit préfixe et un produit suffixe : résultat[i] = (produit de tous les éléments avant i) × (produit de tous les éléments après i). Construisez les produits préfixes lors d’un parcours de gauche à droite, puis multipliez-les par les produits suffixes lors d’un parcours de droite à gauche en utilisant une variable cumulée — aucun tableau supplémentaire n’est nécessaire pour les suffixes.
def product_except_self(nums):
n = len(nums)
result = [1] * n
# Left pass: result[i] = product of nums[:i]
prefix = 1
for i in range(n):
result[i] = prefix
prefix *= nums[i]
# Right pass: multiply in product of nums[i+1:]
suffix = 1
for i in range(n-1, -1, -1):
result[i] *= suffix
suffix *= nums[i]
return result
print(product_except_self([1, 2, 3, 4]))
# [24, 12, 8, 6] O(n) time, O(1) extra spaceSomme préfixe et modulo
Certains problèmes demandent le nombre de sous-tableaux dont la somme est divisible par k. En utilisant les sommes préfixes modulo k, si prefix[j] % k == prefix[i] % k, alors sum(i+1..j) est divisible par k. Une table de hachage qui compte chaque valeur de reste au fur et à mesure du parcours donne une complexité O(n). L’initialisation essentielle est freq[0] = 1 pour prendre en compte les sous-tableaux commençant à l’indice 0.
from collections import defaultdict
def subarray_div_by_k(nums, k):
freq = defaultdict(int)
freq[0] = 1
current = 0
count = 0
for n in nums:
current = (current + n) % k
count += freq[current]
freq[current] += 1
return count
print(subarray_div_by_k([4, 5, 0, -2, -3, 1], 5))
# 7 (seven subarrays divisible by 5)Tableau des différences pour les mises à jour d’intervalles
Un tableau des différences est l’inverse d’une somme préfixe. Étant donné un tableau, précalculez diff[i] = nums[i] - nums[i-1]. Ajouter x à un intervalle [l, r] ne nécessite que deux opérations O(1) sur le tableau des différences : diff[l] += x et diff[r+1] -= x. Après toutes les mises à jour, reconstruisez le tableau de résultat en un seul parcours de somme préfixe. Cela transforme k mises à jour d’intervalles, de O(n×k) en O(n + k).
def apply_range_updates(n, updates):
# updates: list of (l, r, val)
diff = [0] * (n + 1)
for l, r, val in updates:
diff[l] += val
diff[r+1] -= val
# Reconstruct with prefix sum
result = []
running = 0
for i in range(n):
running += diff[i]
result.append(running)
return result
# Add 3 to [1,3], add 1 to [0,2]
print(apply_range_updates(5, [(1,3,3),(0,2,1)]))
# [1, 4, 4, 3, 0]Sommes préfixes dans les problèmes d’entretien
Les sommes préfixes apparaissent dans de nombreuses catégories de problèmes :
- Requêtes sur des intervalles — somme d’un sous-tableau, somme d’un rectangle
- Comptage de sous-tableaux — somme égale à k, divisible par k
- Problèmes de produits — produit de tous les éléments sauf soi-même
- Équilibre — trouver l’indice d’équilibre
- Mises à jour d’intervalles — tableau des différences
# Template: prefix sum + hash map for subarray problems
from collections import defaultdict
def subarray_count_template(nums, target):
"""
Count subarrays with property involving prefix sums.
Adapt 'target' and lookup condition for each problem.
"""
freq = defaultdict(int)
freq[0] = 1 # empty prefix at sum=0
current = 0
count = 0
for n in nums:
current += n
count += freq[current - target] # adjust per problem
freq[current] += 1
return count
print(subarray_count_template([1,2,3,2,1], 3)) # 3Somme cumulée et maximum cumulé
Au-delà des sommes préfixes, de nombreux problèmes utilisent un maximum cumulé ou un minimum cumulé conservé dans une seule variable. Le problème du meilleur moment pour acheter et vendre des actions utilise un prix minimal cumulé ; le calcul de l’eau de pluie piégée depuis la gauche utilise une hauteur maximale cumulée à gauche. Ces schémas ne nécessitent qu’un seul parcours et O(1) espace supplémentaire, ce qui en fait la référence absolue en matière d’efficacité temporelle et spatiale.
def max_profit(prices):
# Running minimum buy price
min_price = float('inf')
max_prof = 0
for price in prices:
if price < min_price:
min_price = price
elif price - min_price > max_prof:
max_prof = price - min_price
return max_prof
def left_max_array(heights):
# Running max from left for trapping rain water
n = len(heights)
left_max = [0] * n
left_max[0] = heights[0]
for i in range(1, n):
left_max[i] = max(left_max[i-1], heights[i])
return left_max
print(max_profit([7,1,5,3,6,4])) # 5Vérification rapide
Vérifiez 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 que les sommes préfixes transforment les requêtes sur des intervalles en O(n) en consultations O(1) grâce au précalcul des sommes cumulées lors d’un seul parcours en O(n), que la combinaison des sommes préfixes et d’une table de hachage permet des solutions en O(n) pour compter les sous-tableaux ayant une somme donnée ou une propriété de divisibilité donnée, et que les tableaux des différences sont l’inverse : ils permettent d’effectuer des mises à jour d’intervalles en O(1), puis de reconstruire le résultat en un seul parcours de somme préfixe à la fin. Nous allons maintenant aborder la technique des deux pointeurs, en commençant par les pointeurs placés aux extrémités opposées.
Questions Fréquemment Posées
La leçon « Sommes préfixes et totaux cumulés » est-elle gratuite ?
Oui — le texte complet de « Sommes préfixes et totaux cumulés » 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 Coding Interview Prep, passe à CoddyKit PRO. Le cours Coding Interview Prep comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Sommes préfixes et totaux cumulés » ?
Construisez des tableaux de sommes préfixes pour répondre à des requêtes de sommes sur intervalles en O(1), puis appliquez cette technique à des problèmes de sous-tableaux, comme celui du sous-tablea… Tu pratiques Coding 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 Coding Interview Prep ?
Aucune expérience préalable n'est requise. Coding 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 « Sommes préfixes et totaux cumulés » ?
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 Coding Interview Prep ?
Oui. Chaque leçon Coding 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
- Bases des tableaux et opérations en place
- Sommes préfixes et totaux cumulés
- Deux pointeurs : extrémités opposées
- Deux pointeurs : lent et rapide