Jeu des sauts I et II
Déterminez l’accessibilité et le nombre minimal de sauts à l’aide d’une approche gloutonne d’élargissement de plage, sans recourir à DP.
Jeu des sauts I et II est une leçon DSA Interview Prep gratuite sur CoddyKit. Ceci est la leçon 3 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.
Jeu de sauts I : pouvez-vous atteindre la fin ?
Jeu de sauts I (LeetCode 55) : étant donné un tableau dans lequel nums[i] représente la longueur maximale du saut depuis l’indice i, déterminez si vous pouvez atteindre le dernier indice en partant de l’indice 0. Pour [2, 3, 1, 1, 4], vous pouvez atteindre la fin (un saut de 2 vous amène à 3, puis 3 vous permet d’atteindre la fin). Pour [3, 2, 1, 0, 4], vous ne le pouvez pas (vous atterrissez toujours sur 0, dont la longueur de saut est 0). Une solution gloutonne s’exécute en O(n).
# Can you reach the last index?
nums1 = [2, 3, 1, 1, 4] # True: 0→1→4 or 0→2→3→4
nums2 = [3, 2, 1, 0, 4] # False: always land on index 3 (value 0)
# At index 3 (value 0): no matter how you get here,
# you can't jump further to reach index 4
print('nums1 last index:', len(nums1)-1)
print('nums2 index 3 jump value:', nums2[3]) # 0 = stuckApproche gloutonne : suivre la portée maximale
L’idée gloutonne de Jeu de sauts I consiste à maintenir max_reach, le plus grand indice accessible jusqu’à présent. À chaque indice i, mettez à jour max_reach = max(max_reach, i + nums[i]). Si, à un moment donné, i > max_reach, l’indice actuel est inaccessible — renvoyez False. Si nous atteignons ou dépassons le dernier indice, renvoyez True. Aucun DP ni retour arrière n’est nécessaire.
def can_jump(nums):
max_reach = 0
for i, jump in enumerate(nums):
if i > max_reach: # can't reach index i
return False
max_reach = max(max_reach, i + jump)
if max_reach >= len(nums) - 1:
return True # early exit
return True
print(can_jump([2, 3, 1, 1, 4])) # True
print(can_jump([3, 2, 1, 0, 4])) # False
print(can_jump([0])) # True (already at last index)
print(can_jump([1, 0, 0])) # FalseTracer Jeu de sauts I
Tracez [3, 2, 1, 0, 4] : i=0, jump=3, max_reach=3. i=1, jump=2, max_reach=max(3,3)=3. i=2, jump=1, max_reach=max(3,3)=3. i=3, jump=0, max_reach=max(3,3)=3. i=4, i=4 > max_reach=3 → return False. L’algorithme identifie correctement que l’indice 4 est inaccessible. Chaque chemin depuis l’indice 0 est bloqué, car le 0 à l’indice 3 limite max_reach à 3.
def can_jump_trace(nums):
max_reach = 0
for i, jump in enumerate(nums):
print(f'i={i}, jump={jump}, max_reach before={max_reach}', end='')
if i > max_reach:
print(' → UNREACHABLE')
return False
max_reach = max(max_reach, i + jump)
print(f' → max_reach={max_reach}')
return True
print('Result:', can_jump_trace([3, 2, 1, 0, 4]))Jeu de sauts II : nombre minimal de sauts
Jeu de sauts II (LeetCode 45) demande le nombre minimal de sauts pour atteindre le dernier indice, qui est toujours accessible. L’approche gloutonne utilise une stratégie d’extension de portée : maintenez la portée maximale du saut actuel (curr_end) et celle du saut suivant (farthest). Lorsque vous avez épuisé la portée du saut actuel, vous devez effectuer un saut — incrémentez jumps et définissez curr_end = farthest.
def jump(nums):
n = len(nums)
if n == 1: return 0 # already at destination
jumps = 0
curr_end = 0 # end of current jump's range
farthest = 0 # farthest reachable in next jump
for i in range(n - 1): # don't jump from last index
farthest = max(farthest, i + nums[i])
if i == curr_end: # exhausted current jump range
jumps += 1
curr_end = farthest
if curr_end >= n - 1: break
return jumps
print(jump([2, 3, 1, 1, 4])) # 2 (0→1→4)
print(jump([2, 3, 0, 1, 4])) # 2 (0→1→4)
print(jump([1, 2, 1, 1, 1])) # 3Visualiser Jeu de sauts II
Considérez Jeu de sauts II comme une approche BFS niveau par niveau, sans le coût supplémentaire de la file. Chaque saut correspond à un niveau de BFS. curr_end est la limite du niveau actuel. farthest est le plus grand indice accessible au niveau suivant. Lorsque vous avez fini de parcourir le niveau actuel (i == curr_end), vous avez déterminé la limite du niveau suivant et devez incrémenter le nombre de sauts. Il s’agit d’un BFS sur un graphe implicite, en O(n) en temps et O(1) en espace.
def jump_traced(nums):
n = len(nums)
jumps = curr_end = farthest = 0
for i in range(n - 1):
farthest = max(farthest, i + nums[i])
print(f'i={i}: farthest={farthest}, curr_end={curr_end}')
if i == curr_end:
jumps += 1
curr_end = farthest
print(f' → JUMP #{jumps}, new range ends at {curr_end}')
if curr_end >= n - 1: break
return jumps
print('Min jumps:', jump_traced([2, 3, 1, 1, 4]))Pourquoi l’approche gloutonne est correcte pour Jeu de sauts II
Pourquoi l’approche gloutonne, qui étend toujours la portée jusqu’au point le plus éloigné, donne-t-elle le nombre minimal de sauts ? Argument d’échange : supposons que la solution optimale effectue un saut qui n’atteint pas le point le plus éloigné. Nous pouvons toujours étendre ce saut jusqu’à farthest sans coût supplémentaire : il s’agit toujours d’un seul saut. En prenant toujours la portée maximale à chaque saut, nous garantissons le nombre minimal de sauts nécessaires. Toute solution qui parcourt une distance moindre à chaque saut ne peut pas faire mieux et aurait besoin de davantage de sauts pour couvrir la même distance.
# Correctness verification: compare to BFS
from collections import deque
def jump_bfs(nums):
n = len(nums)
if n == 1: return 0
visited = [False] * n
visited[0] = True
queue = deque([0])
level = 0
while queue:
level += 1
for _ in range(len(queue)):
pos = queue.popleft()
for j in range(1, nums[pos] + 1):
nxt = pos + j
if nxt >= n - 1: return level
if not visited[nxt]:
visited[nxt] = True
queue.append(nxt)
return -1
# Both should give same results
for nums in [[2,3,1,1,4],[2,3,0,1,4],[1,2,1,1,1]]:
print(jump(nums), '==', jump_bfs(nums))Alternative avec DP pour Jeu de sauts II
Une solution avec DP : dp[i] = nombre minimal de sauts pour atteindre l’indice i. Pour chaque position j, mettez à jour toutes les positions accessibles : dp[j+k] = min(dp[j+k], dp[j]+1) pour k dans 1..nums[j]. Cette solution s’exécute en O(n × max_jump) en temps et utilise O(n) en espace — elle est donc beaucoup plus lente que l’approche gloutonne en O(n). L’approche gloutonne est préférable ici ; la DP est présentée à titre de comparaison, pour montrer comment l’approche gloutonne peut éviter la boucle interne.
def jump_dp(nums):
n = len(nums)
dp = [float('inf')] * n
dp[0] = 0
for j in range(n):
for k in range(1, nums[j] + 1):
if j + k < n:
dp[j+k] = min(dp[j+k], dp[j] + 1)
return dp[n-1]
print(jump_dp([2, 3, 1, 1, 4])) # 2
print(jump_dp([1, 2, 1, 1, 1])) # 3
# Greedy is O(n), DP is O(n * max_jump)
# For large inputs with big jump values, greedy is much fasterJeu de sauts III : atteindre l’indice zéro
Jeu de sauts III (LeetCode 1306) : partez d’un indice donné ; depuis l’indice i, sautez vers i + nums[i] ou i - nums[i]. Pouvez-vous atteindre un indice dont la valeur est 0 ? Il s’agit d’un problème d’accessibilité (BFS/DFS), et non d’un problème de minimisation — l’approche gloutonne ne s’applique pas. Utilisez un BFS avec un ensemble des positions visitées pour éviter les cycles. Complexité temporelle : O(n).
from collections import deque
def can_reach(arr, start):
n = len(arr)
visited = set()
queue = deque([start])
while queue:
idx = queue.popleft()
if arr[idx] == 0: return True
if idx in visited: continue
visited.add(idx)
for nxt in [idx + arr[idx], idx - arr[idx]]:
if 0 <= nxt < n and nxt not in visited:
queue.append(nxt)
return False
print(can_reach([4,2,3,0,3,1,2], 5)) # True (5→4→1→3, arr[3]=0)
print(can_reach([3,0,2,1,2], 2)) # False (can't reach index 1, arr[1]=0)Jeu de sauts VII : accessibilité avec une portée
Jeu de sauts VII (LeetCode 1871) : pouvez-vous parcourir une chaîne binaire en sautant de l’indice 0 au dernier indice, sachant que depuis la position i, vous pouvez sauter vers n’importe quel ‘0’ dans [i+minJump, i+maxJump] ? Utilisez une somme sur fenêtre glissante appliquée au tableau des positions accessibles. Maintenez une somme préfixe des positions accessibles ; une position j est accessible s’il existe une position accessible dans [j-maxJump, j-minJump].
def can_reach_vii(s, min_jump, max_jump):
n = len(s)
reach = [False] * n
reach[0] = True
pre = [0] * (n + 1) # prefix sum of reachable positions
pre[1] = 1
for j in range(1, n):
# Window sum: any reachable position in [j-maxJump, j-minJump]?
lo = max(0, j - max_jump)
hi = max(0, j - min_jump + 1)
window_sum = pre[hi] - pre[lo]
if s[j] == '0' and window_sum > 0:
reach[j] = True
pre[j+1] = pre[j] + (1 if reach[j] else 0)
return reach[n-1]
print(can_reach_vii('011010', 2, 3)) # True
print(can_reach_vii('01101110', 2, 3)) # FalseComparaison des solutions gloutonne et BFS
Jeu de sauts II possède deux approches équivalentes en O(n) : l’extension gloutonne de portée et le parcours BFS niveau par niveau. L’approche gloutonne utilise O(1) espace, sans file, tandis que BFS utilise O(n) pour l’ensemble des positions visitées. En entretien, l’approche gloutonne est privilégiée pour son efficacité spatiale. Cependant, BFS est plus facile à dériver en premier — si vous avez du mal à trouver la solution gloutonne, codez d’abord BFS pour obtenir une solution fonctionnelle, puis optimisez-la. Les deux approches calculent correctement le nombre minimal de sauts.
# Both approaches are O(n) time
# Greedy: O(1) space — preferred in interviews
# BFS: O(n) space — easier to derive
# Greedy advantage: no auxiliary data structures
def jump_greedy(nums):
n, jumps, curr, far = len(nums), 0, 0, 0
for i in range(n-1):
far = max(far, i+nums[i])
if i == curr: jumps += 1; curr = far
return jumps
# BFS equivalence: each level = one jump
from collections import deque
def jump_bfs(nums):
n = len(nums)
if n == 1: return 0
q, visited, level = deque([0]), {0}, 0
while q:
level += 1
for _ in range(len(q)):
pos = q.popleft()
for j in range(1, nums[pos]+1):
nxt = pos + j
if nxt >= n-1: return level
if nxt not in visited: visited.add(nxt); q.append(nxt)
return -1
nums = [2,3,1,1,4]
print(jump_greedy(nums), '==', jump_bfs(nums)) # both 2Résumé de la complexité des jeux de sauts
Résumé de la complexité des variantes de Jeu de sauts : Jeu I (accessibilité) : O(n) en temps, O(1) en espace. Jeu II (sauts minimaux avec approche gloutonne) : O(n) en temps, O(1) en espace. Jeu II (BFS) : O(n) en temps, O(n) en espace. Jeu II (DP) : O(n × max_jump) en temps, O(n) en espace. Jeu III (BFS/DFS) : O(n) en temps, O(n) en espace pour les positions visitées. Jeu VII (fenêtre glissante) : O(n) en temps, O(n) en espace. Présentez toujours en entretien la solution gloutonne O(n) O(1) pour Jeu de sauts I et II.
# Comparison: all versions on the same input
nums = [2, 3, 1, 1, 4]
# Jump I
def can_jump(nums):
mr = 0
for i, j in enumerate(nums):
if i > mr: return False
mr = max(mr, i+j)
return True
# Jump II greedy O(n) O(1)
def jump_min(nums):
n, jumps, curr, far = len(nums), 0, 0, 0
for i in range(n-1):
far = max(far, i+nums[i])
if i == curr:
jumps += 1; curr = far
if curr >= n-1: break
return jumps
print('Can reach:', can_jump(nums)) # True
print('Min jumps:', jump_min(nums)) # 2
print('Complexity: O(n) time, O(1) space')Vérification rapide
Évaluez 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 que : Jeu de sauts I utilise le suivi glouton de max_reach pour déterminer l’accessibilité en O(n) en temps et O(1) en espace, Jeu de sauts II utilise l’extension de portée avec curr_end et farthest pour compter le nombre minimal de sauts en O(n) et O(1), et l’extension gloutonne de portée équivaut à un BFS niveau par niveau sans le coût supplémentaire de la file. Nous allons maintenant appliquer le raisonnement glouton au délai de refroidissement de l’ordonnanceur de tâches et aux problèmes de faisabilité circulaire de la station-service.
Questions Fréquemment Posées
La leçon « Jeu des sauts I et II » est-elle gratuite ?
Oui — le texte complet de « Jeu des sauts I et II » 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 « Jeu des sauts I et II » ?
Déterminez l’accessibilité et le nombre minimal de sauts à l’aide d’une approche gloutonne d’élargissement de plage, sans recourir à DP. 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 3 sur 4.
Combien de temps prend la leçon « Jeu des sauts I et II » ?
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
- Glouton ou DP : quand utiliser chaque approche
- Planification et fusion d’intervalles
- Jeu des sauts I et II
- Planificateur de tâches et station-service