Ballons à éclater : DP sur intervalles inversée
Résolvez le problème burst-balloons en raisonnant à rebours : choisissez le dernier ballon à éclater dans chaque intervalle plutôt que le premier.
Ballons à éclater : DP sur intervalles inversée est une leçon DSA Interview Prep gratuite sur CoddyKit. Ceci est la leçon 4 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.
Le problème de l’éclatement des ballons
Étant donnés n ballons de valeurs nums, faire éclater le ballon i rapporte nums[i-1] * nums[i] * nums[i+1] pièces (le produit de sa valeur et de celles de ses voisins actuels). Après son éclatement, ses voisins deviennent adjacents. Trouvez le nombre maximal de pièces que vous pouvez obtenir en faisant éclater tous les ballons. La simulation naïve est difficile, car l’éclatement modifie les voisins — la DP par intervalles inversée contourne élégamment cette difficulté.
Pourquoi la simulation en avant échoue
Si nous essayons de définir dp[i][j] comme le nombre maximal de pièces obtenu en faisant éclater les ballons de l’intervalle [i, j] et que nous réfléchissons au premier ballon à éclater, nous rencontrons un problème : faire éclater le ballon k en premier signifie que nums[k-1] et nums[k+1] doivent être ses voisins actuels — mais ces ballons pourraient être éclatés plus tard, ce qui modifierait dynamiquement les voisins. L’état est difficile à définir proprement dans le sens direct.
Idée clé : raisonner à rebours
L’astuce consiste à réfléchir au ballon qui sera le dernier à éclater dans l’intervalle [i, j]. Lorsque le ballon k est le dernier à éclater dans [i, j], tous les autres ballons de [i, j] ont déjà disparu. Les voisins du ballon k sont donc exactement nums[i-1] et nums[j+1] — les ballons frontières situés juste à l’extérieur de l’intervalle. Le calcul des pièces rapportées par le dernier éclatement devient ainsi déterministe : il ne dépend pas de l’ordre des éclatements précédents.
Définition de l’état et de la récurrence
Ajoutez des ballons sentinelles : ajoutez 1 au début et à la fin de nums pour obtenir nums = [1] + nums + [1]. Définissez dp[i][j] comme le nombre maximal de pièces obtenu en faisant éclater tous les ballons strictement compris entre les indices i et j (bornes exclues), où nums[i] et nums[j] sont les ballons frontières qui subsistent. Récurrence : pour chaque ballon candidat k dans (i, j) comme dernier ballon à éclater : dp[i][j] = max(dp[i][k] + dp[k][j] + nums[i]*nums[k]*nums[j]).
# With sentinels: nums = [1] + original + [1]
# dp[i][j] = max coins from bursting all balloons in open interval (i, j)
# k = last balloon to burst in (i,j)
# dp[i][j] = max over k in (i,j): dp[i][k] + dp[k][j] + nums[i]*nums[k]*nums[j]Implémentation complète
Nous complétons le tableau avec des sentinelles, initialisons la table DP à zéro (intervalle vide = 0 pièce), puis la remplissons par longueur d’intervalle croissante. La réponse finale est dp[0][n+1] : elle représente le nombre maximal de pièces obtenu en faisant éclater tous les ballons d’origine, les sentinelles servant de frontières permanentes.
def maxCoins(nums):
nums = [1] + nums + [1]
n = len(nums)
dp = [[0]*n for _ in range(n)]
# length of open interval (i, j) exclusive: j - i - 1 balloons inside
for length in range(2, n): # length = j - i
for i in range(0, n - length):
j = i + length
for k in range(i+1, j): # k is last burst in (i, j)
coins = dp[i][k] + dp[k][j] + nums[i]*nums[k]*nums[j]
dp[i][j] = max(dp[i][j], coins)
return dp[0][n-1]
print(maxCoins([3, 1, 5, 8])) # 167Traçage de l’exemple
Pour [3, 1, 5, 8], complété par des sentinelles pour obtenir [1, 3, 1, 5, 8, 1] (indices 0 à 5). Nous cherchons dp[0][5]. Pour les intervalles de longueur 2 (un ballon à l’intérieur) : dp[0][2] = 1*3*1=3, dp[1][3]=3*1*5=15, dp[2][4]=1*5*8=40, dp[3][5]=5*8*1=40. En poursuivant la construction, l’optimum consiste à faire éclater 1 en dernier parmi {3,1,5,8}, après avoir fait éclater ses voisins, pour un total de 167 pièces.
Analyse de la complexité
Il y a O(n²) intervalles et, pour chaque intervalle, nous essayons O(n) points de séparation, ce qui donne une complexité temporelle en O(n³). L’espace utilisé est de O(n²) pour la table DP. Pour n = 500 ballons, cela représente 125 millions d’opérations, ce qui reste réalisable avec les contraintes d’un entretien. L’ajout de sentinelles simplifie la gestion des frontières : sans elles, il faudrait vérifier explicitement si i-1 et j+1 restent dans les limites du tableau.
Alternative descendante avec mémorisation
La même solution peut s’écrire de haut en bas avec @lru_cache, ce qui peut être plus intuitif à élaborer pendant un entretien. Définissez solve(i, j) comme le nombre maximal de pièces dans l’intervalle ouvert (i, j). La fonction essaie toutes les valeurs de k comme dernier ballon à éclater et mémorise les résultats. Les deux approches ont exactement les mêmes complexités temporelle et spatiale.
from functools import lru_cache
def maxCoins_memo(nums):
nums = [1] + nums + [1]
n = len(nums)
@lru_cache(maxsize=None)
def solve(i, j):
if j - i < 2: # no balloons between i and j
return 0
return max(
solve(i, k) + solve(k, j) + nums[i]*nums[k]*nums[j]
for k in range(i+1, j)
)
return solve(0, n-1)
print(maxCoins_memo([3, 1, 5, 8])) # 167Erreur courante : définition de la DP en avant
Une erreur courante consiste à définir dp[i][j] comme le nombre de pièces obtenu lorsque le premier ballon de [i,j] est éclaté, plutôt que le dernier. Cette approche échoue, car le calcul des pièces du premier éclatement dépend des ballons voisins qui n’ont pas encore été éclatés — et l’état de ces voisins change au fur et à mesure de la progression de l’algorithme. Pensez toujours au dernier élément dans la DP par intervalles lorsque les frontières dépendent des éléments restants.
Pourquoi des valeurs sentinelles égales à 1 ?
Les sentinelles de valeur 1 sont choisies parce qu’elles jouent le rôle d’éléments neutres pour la multiplication. Lorsqu’un ballon frontière est le dernier à éclater, sa valeur en pièces est boundary * last * boundary = 1 * last * 1 = last. Utiliser 0 donnerait 0 pièce, ce qui serait incorrect, tandis que d’autres valeurs fausseraient le calcul. L’astuce des sentinelles réunit proprement tous les cas de frontière sans traiter séparément les ballons situés tout à gauche et tout à droite.
Comparaison avec la DP par intervalles standard
Dans la DP par intervalles standard (chaînage de matrices), le point de séparation k indique où diviser le problème en deux sous-problèmes résolus indépendamment. Dans le problème des ballons à éclater, k est le dernier ballon à éclater dans l’intervalle, ce qui rend les deux sous-intervalles [i,k] et [k,j] indépendants, puisque k est encore présent comme frontière. Cette perspective inversée est l’idée ingénieuse qui permet de résoudre le problème des ballons à éclater avec une DP par intervalles.
Vérification rapide
Vérifiez votre compréhension des concepts de Structures de données et 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 : la simulation vers l’avant échoue, car l’éclatement des ballons modifie les voisins de manière imprévisible, l’idée inverse consiste à définir k comme le dernier ballon éclaté dans un intervalle, ce qui fait de nums[i] et nums[j] ses voisins, et la récurrence dp[i][j] = max(dp[i][k] + dp[k][j] + nums[i]*nums[k]*nums[j]) avec un remplissage par des sentinelles fournit une solution en O(n³). Ensuite, nous passons à la programmation dynamique du sac à dos, en commençant par le sac à dos classique 0/1 et son optimisation de l’espace mémoire.
Questions Fréquemment Posées
La leçon « Ballons à éclater : DP sur intervalles inversée » est-elle gratuite ?
Oui — le texte complet de « Ballons à éclater : DP sur intervalles inversée » 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 « Ballons à éclater : DP sur intervalles inversée » ?
Résolvez le problème burst-balloons en raisonnant à rebours : choisissez le dernier ballon à éclater dans chaque intervalle plutôt que le premier. 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 4 sur 4.
Combien de temps prend la leçon « Ballons à éclater : DP sur intervalles inversée » ?
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
- Schéma de DP sur les intervalles et ordre de remplissage
- Plus longue sous-séquence et sous-chaîne palindromiques
- Partitionnement palindromique II
- Ballons à éclater : DP sur intervalles inversée