0Pricing
Coding Interview Prep · Pelajaran

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 = stuck

Serakah: 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]))        # False

Menelusuri 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])) # 3

Memvisualisasikan 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 faster

Permainan 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))  # False

Membandingkan 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 2

Ringkasan 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

  1. Greedy vs DP: Kapan Menggunakan Masing-Masing
  2. Penjadwalan dan Penggabungan Interval
  3. Jump Game I dan II
  4. Penjadwal Tugas dan Pompa Bensin
← Kembali ke Coding Interview Prep