Jump Game I en II
Bepaal bereikbaarheid en het minimumaantal sprongen met een greedy-aanpak die bereiken uitbreidt en geen DP nodig heeft.
Jump Game I en II is een gratis Voorbereiding op programmeerinterviews-les op CoddyKit. Dit is les 3 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Voorbereiding op programmeerinterviews. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Voorbereiding op programmeerinterviews bevat in totaal 4 lessen.
Sprongspel I: kun je het einde bereiken?
Sprongspel I (LeetCode 55): gegeven een array waarin nums[i] de maximale spronglengte vanaf index i aangeeft, bepaal je of je vanaf index 0 de laatste index kunt bereiken. Bij [2, 3, 1, 1, 4] kun je het einde bereiken (sprong 2→3, waarna 3 je naar het einde brengt). Bij [3, 2, 1, 0, 4] lukt dat niet (je komt altijd op 0 terecht, en die heeft een spronglengte van 0). Een greedy-oplossing draait in 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 = stuckGreedy: maximaal bereik bijhouden
Het greedy-inzicht voor Sprongspel I: houd max_reach bij, de verste index die tot nu toe bereikbaar is. Werk bij elke index i max_reach = max(max_reach, i + nums[i]) bij. Als op enig moment i > max_reach geldt, is de huidige index onbereikbaar — geef False terug. Als we de laatste index bereiken of voorbijgaan, geven we True terug. Je hebt geen DP of backtracking nodig.
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])) # FalseSprongspel I traceren
Traceer [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. Het algoritme stelt correct vast dat index 4 onbereikbaar is. Elk pad vanaf index 0 loopt vast, omdat de 0 op index 3 max_reach beperkt tot 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]))Sprongspel II: minimaal aantal sprongen
Bij Sprongspel II (LeetCode 45) zoek je het minimale aantal sprongen om de laatste index te bereiken (die altijd bereikbaar is). De greedy-aanpak gebruikt een strategie waarbij je het bereik uitbreidt: houd het verste bereik van de huidige sprong (curr_end) en het verste bereik van de volgende sprong (farthest) bij. Wanneer je het bereik van de huidige sprong hebt opgebruikt, moet je springen — verhoog jumps en stel curr_end = farthest in.
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])) # 3Sprongspel II visualiseren
Zie Sprongspel II als een BFS-niveau-voor-niveau-aanpak zonder de overhead van de wachtrij. Elke sprong komt overeen met één BFS-niveau. curr_end is de grens van het huidige niveau. farthest is de maximale index die in het volgende niveau bereikbaar is. Wanneer je het huidige niveau volledig hebt gescand (i == curr_end), heb je de grens van het volgende niveau bepaald en moet je het aantal sprongen verhogen. Dit is BFS op een impliciete graaf in O(n)-tijd en met O(1)-geheugenruimte.
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]))Waarom greedy correct is voor Sprongspel II
Waarom levert greedy, waarbij je altijd tot het verste punt uitbreidt, het minimale aantal sprongen op? Uitwisselingsargument: stel dat de optimale oplossing een sprong maakt die het verste punt niet bereikt. Dan kunnen we die sprong altijd uitbreiden tot farthest zonder extra kosten — het blijft één sprong. Door per sprong altijd het maximale bereik te nemen, garanderen we het minimale aantal benodigde sprongen. Een oplossing die per sprong een kleiner bereik neemt, kan het niet beter doen en heeft meer sprongen nodig om dezelfde afstand af te leggen.
# 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))DP-alternatief voor Sprongspel II
Een DP-oplossing: dp[i] = het minimale aantal sprongen om index i te bereiken. Werk voor elke positie j alle bereikbare posities bij: dp[j+k] = min(dp[j+k], dp[j]+1) voor k in 1..nums[j]. Dit kost O(n × max_jump)-tijd en O(n)-geheugenruimte — veel langzamer dan de greedy-oplossing met O(n). Greedy is hier beter; DP wordt ter vergelijking getoond om te laten zien hoe greedy de binnenste lus kan vermijden.
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 fasterSprongspel III: index nul bereiken
Sprongspel III (LeetCode 1306): begin op een gegeven index; vanaf index i spring je naar i + nums[i] of i - nums[i]. Kun je een index met waarde 0 bereiken? Dit is een bereikbaarheidsprobleem (BFS/DFS), geen minimalisatieprobleem — greedy is hier niet van toepassing. Gebruik BFS met een verzameling bezochte posities om cycli te voorkomen. Tijdcomplexiteit: 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)Sprongspel VII: bereikbaar met een bereik
Sprongspel VII (LeetCode 1871): kun je een binaire tekenreeks doorlopen door van index 0 naar de laatste index te springen, waarbij je vanaf positie i naar elke '0' in [i+minJump, i+maxJump] kunt springen? Gebruik een som over een schuivend venster van de bereikbare array. Houd een prefixsom van bereikbare posities bij; een positie j is bereikbaar als er een bereikbare positie in [j-maxJump, j-minJump] staat.
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)) # FalseGreedy- en BFS-oplossingen vergelijken
Sprongspel II heeft twee gelijkwaardige O(n)-aanpakken: greedy-bereikuitbreiding en BFS-niveaudoorloop. De greedy-aanpak gebruikt O(1)-geheugenruimte (geen wachtrij), terwijl BFS O(n) gebruikt voor de verzameling bezochte posities. Tijdens een sollicitatiegesprek heeft greedy de voorkeur vanwege de geheugenefficiëntie. BFS is echter gemakkelijker eerst af te leiden — als je moeite hebt om de greedy-oplossing te zien, schrijf dan BFS om een werkende oplossing te krijgen en optimaliseer die daarna. Beide berekenen correct het minimale aantal sprongen.
# 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 2Complexiteitsoverzicht van Sprongspel
Complexiteitsoverzicht van de varianten van Sprongspel: Sprong I (bereikbaarheid): O(n)-tijd, O(1)-geheugenruimte. Sprong II (greedy voor minimaal aantal sprongen): O(n)-tijd, O(1)-geheugenruimte. Sprong II (BFS): O(n)-tijd, O(n)-geheugenruimte. Sprong II (DP): O(n × max_jump)-tijd, O(n)-geheugenruimte. Sprong III (BFS/DFS): O(n)-tijd, O(n)-geheugenruimte voor bezochte posities. Sprong VII (schuivend venster): O(n)-tijd, O(n)-geheugenruimte. Presenteer tijdens sollicitatiegesprekken altijd de greedy-oplossing met O(n)-tijd en O(1)-geheugenruimte voor Sprong I en 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')Korte controle
Toets je begrip van de concepten uit Data Structures & Algorithms — Coding Interview Prep in deze les.
Samenvatting van de les
In deze les heb je geleerd: Sprongspel I gebruikt greedy-tracking van max_reach om bereikbaarheid te bepalen in O(n)-tijd en met O(1)-geheugenruimte, Sprongspel II gebruikt bereikuitbreiding met curr_end en farthest om het minimale aantal sprongen te tellen in O(n)-tijd en met O(1)-geheugenruimte, en greedy-bereikuitbreiding is gelijkwaardig aan BFS-niveau voor niveau, maar zonder de overhead van een wachtrij. Hierna passen we greedy-redeneringen toe op de afkoelperiode van het taakplanningsprobleem en op de problemen rond de haalbaarheid van een rondrit bij tankstations.
Leer Voorbereiding op programmeerinterviews met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 90
- Lessen
- 360
Veelgestelde vragen
Is de les “Jump Game I en II” gratis?
Ja — de volledige tekst van “Jump Game I en II” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Voorbereiding op programmeerinterviews wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Voorbereiding op programmeerinterviews bevat in totaal 4 lessen.
Wat leer ik in “Jump Game I en II”?
Bepaal bereikbaarheid en het minimumaantal sprongen met een greedy-aanpak die bereiken uitbreidt en geen DP nodig heeft. Je oefent met Voorbereiding op programmeerinterviews door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Voorbereiding op programmeerinterviews te beginnen?
Ervaring vooraf is niet nodig. Voorbereiding op programmeerinterviews op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 3 van 4.
Hoe lang duurt de les “Jump Game I en II”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Voorbereiding op programmeerinterviews?
Ja. Elke les over Voorbereiding op programmeerinterviews bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Greedy versus DP: wanneer gebruikt u welke methode
- Intervalplanning en samenvoegen
- Jump Game I en II
- Task Scheduler en Gas Station