Jump Game I dan II
Tentukan keterjangkauan dan jumlah lompatan minimum menggunakan pendekatan greedy yang memperluas rentang, tanpa memerlukan DP
Jump Game I dan II adalah pelajaran Coding Interview Prep gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Coding Interview Prep, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Coding Interview Prep mencakup 4 pelajaran total.
Permainan Lompatan I: Dapatkah Anda Mencapai Akhir?
Permainan Lompatan I (LeetCode 55): diberikan sebuah larik yang nums[i]-nya merupakan panjang lompatan maksimum dari indeks i, tentukan apakah Anda dapat mencapai indeks terakhir mulai dari indeks 0. Untuk [2, 3, 1, 1, 4], Anda dapat mencapai akhir (melompat 2→3, lalu 3 membawa Anda ke akhir). Untuk [3, 2, 1, 0, 4], Anda tidak dapat mencapainya (Anda selalu mendarat di 0, yang memiliki panjang lompatan 0). Solusi serakah berjalan dalam 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 = stuckSerakah: Lacak Jangkauan Maksimum
Wawasan serakah untuk Permainan Lompatan I: pertahankan max_reach, yaitu indeks terjauh yang sejauh ini dapat dicapai. Pada setiap indeks i, perbarui max_reach = max(max_reach, i + nums[i]). Jika sewaktu-waktu i > max_reach, indeks saat ini tidak dapat dicapai — kembalikan Salah. Jika kita mencapai atau melewati indeks terakhir, kembalikan Benar. Tidak diperlukan DP atau penelusuran mundur.
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])) # FalseMenelusuri Permainan Lompatan I
Telusuri [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. Algoritme dengan tepat mengidentifikasi bahwa indeks 4 tidak dapat dicapai. Setiap jalur dari indeks 0 terjebak karena angka 0 pada indeks 3 membatasi max_reach hingga 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]))Permainan Lompatan II: Jumlah Lompatan Minimum
Permainan Lompatan II (LeetCode 45) meminta jumlah lompatan minimum untuk mencapai indeks terakhir (yang selalu dapat dicapai). Pendekatan serakah menggunakan strategi perluasan jangkauan: pertahankan jangkauan terjauh lompatan saat ini (curr_end) dan jangkauan terjauh lompatan berikutnya (farthest). Saat jangkauan lompatan saat ini habis, Anda harus melakukan lompatan — naikkan jumps dan tetapkan 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])) # 3Memvisualisasikan Permainan Lompatan II
Anggap Permainan Lompatan II sebagai pendekatan BFS tingkat demi tingkat tanpa beban tambahan berupa antrean. Setiap lompatan setara dengan satu tingkat BFS. curr_end adalah batas tingkat saat ini. farthest adalah indeks maksimum yang dapat dicapai pada tingkat berikutnya. Saat selesai memindai tingkat saat ini (i == curr_end), Anda telah menentukan batas tingkat berikutnya dan harus menambah hitungan lompatan. Ini adalah BFS pada graf implisit dengan waktu O(n) dan ruang O(1).
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]))Mengapa Strategi Serakah Benar untuk Lompatan II
Mengapa strategi serakah (selalu memperluas hingga titik terjauh) menghasilkan jumlah lompatan minimum? Argumen pertukaran: misalkan solusi optimal melakukan lompatan yang tidak mencapai titik terjauh. Kita selalu dapat memperluas lompatan tersebut hingga mencapai farthest tanpa biaya tambahan — tetap hanya satu lompatan. Dengan selalu mengambil jangkauan maksimum pada setiap lompatan, kita menjamin jumlah lompatan minimum yang diperlukan. Solusi apa pun yang mengambil jangkauan lebih pendek pada setiap lompatan tidak dapat memberikan hasil yang lebih baik dan akan memerlukan lebih banyak lompatan untuk menempuh jarak yang sama.
# 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))Alternatif DP untuk Permainan Lompatan II
Solusi DP: dp[i] = jumlah lompatan minimum untuk mencapai indeks i. Untuk setiap posisi j, perbarui semua posisi yang dapat dicapai: dp[j+k] = min(dp[j+k], dp[j]+1) untuk k dalam 1..nums[j]. Solusi ini berjalan dalam waktu O(n × lompatan_maksimum) dan ruang O(n) — jauh lebih lambat daripada solusi serakah O(n). Solusi serakah lebih unggul di sini; DP ditampilkan sebagai perbandingan untuk menunjukkan bagaimana strategi serakah dapat menghindari perulangan bagian dalam.
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 fasterPermainan Lompatan III: Mencapai Indeks Nol
Permainan Lompatan III (LeetCode 1306): mulai dari indeks tertentu; dari indeks i, lompat ke i + nums[i] atau i - nums[i]. Dapatkah Anda mencapai indeks mana pun yang nilainya 0? Ini adalah masalah keterjangkauan (BFS/DFS), bukan masalah minimisasi — strategi serakah tidak berlaku. Gunakan BFS dengan himpunan posisi yang telah dikunjungi untuk menghindari siklus. Waktu: 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)Permainan Lompatan VII: Dapat Dicapai dengan Jangkauan
Permainan Lompatan VII (LeetCode 1871): dapatkah Anda menelusuri teks biner dengan melompat dari indeks 0 ke indeks terakhir, dengan dari posisi i Anda dapat melompat ke angka '0' mana pun dalam [i+minJump, i+maxJump]? Gunakan jumlah jendela geser pada larik posisi yang dapat dicapai. Pertahankan jumlah prefiks posisi yang dapat dicapai; posisi j dapat dicapai jika terdapat posisi yang dapat dicapai dalam [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)) # FalseMembandingkan Solusi Serakah dan BFS
Permainan Lompatan II memiliki dua pendekatan O(n) yang setara: perluasan jangkauan serakah dan penelusuran BFS tingkat demi tingkat. Pendekatan serakah menggunakan ruang O(1) (tanpa antrean), sedangkan BFS menggunakan O(n) untuk himpunan posisi yang telah dikunjungi. Dalam wawancara, strategi serakah lebih disukai karena efisiensi ruangnya. Namun, BFS lebih mudah diturunkan terlebih dahulu — jika Anda kesulitan menemukan solusi serakah, tulis kode BFS untuk mendapatkan solusi yang berfungsi, lalu optimalkan. Keduanya menghitung jumlah lompatan minimum dengan benar.
# 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 2Ringkasan Kompleksitas Permainan Lompatan
Ringkasan kompleksitas di seluruh variasi Permainan Lompatan: Permainan Lompatan I (keterjangkauan): waktu O(n), ruang O(1). Permainan Lompatan II (lompatan minimum serakah): waktu O(n), ruang O(1). Permainan Lompatan II (BFS): waktu O(n), ruang O(n). Permainan Lompatan II (DP): waktu O(n × lompatan_maksimum), ruang O(n). Permainan Lompatan III (BFS/DFS): waktu O(n), ruang O(n) untuk posisi yang telah dikunjungi. Permainan Lompatan VII (jendela geser): waktu O(n), ruang O(n). Selalu sajikan solusi serakah O(n) O(1) untuk Permainan Lompatan I dan II dalam wawancara.
# 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')Pemeriksaan Singkat
Uji pemahaman Anda tentang konsep Struktur Data & Algoritma — Persiapan Wawancara Pemrograman dari pelajaran ini.
Rangkuman Pelajaran
Dalam pelajaran ini Anda mempelajari: Permainan Lompatan I menggunakan pelacakan max_reach secara serakah untuk menentukan keterjangkauan dalam waktu O(n) dan ruang O(1), Permainan Lompatan II menggunakan perluasan jangkauan dengan curr_end dan farthest untuk menghitung jumlah lompatan minimum dalam waktu O(n) dan ruang O(1), dan perluasan jangkauan serakah setara dengan BFS tingkat demi tingkat tanpa beban tambahan berupa antrean. Berikutnya kita akan menerapkan penalaran serakah pada masa jeda Penjadwal Tugas dan masalah kelayakan melingkar Stasiun Bahan Bakar.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Jump Game I dan II” gratis?
Ya — teks lengkap “Jump Game I dan II” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Coding Interview Prep, upgrade ke CoddyKit PRO. Kursus Coding Interview Prep mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Jump Game I dan II”?
Tentukan keterjangkauan dan jumlah lompatan minimum menggunakan pendekatan greedy yang memperluas rentang, tanpa memerlukan DP Kamu berlatih Coding Interview Prep dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Coding Interview Prep?
Tidak diperlukan pengalaman sebelumnya. Coding Interview Prep di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.
Berapa lama pelajaran “Jump Game I dan II” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Coding Interview Prep ini?
Ya. Setiap pelajaran Coding Interview Prep menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Greedy vs DP: Kapan Menggunakan Masing-Masing
- Penjadwalan dan Penggabungan Interval
- Jump Game I dan II
- Penjadwal Tugas dan Pompa Bensin