0Pricing
DSA Interview Prep · Pelajaran

Decode Ways dan Penghitungan Jalur

Selesaikan decode-ways (pemetaan digit ke huruf) sebagai DP mirip Fibonacci, lalu hitung jalur pada tangga dengan ukuran langkah variabel.

Decode Ways dan Penghitungan Jalur adalah pelajaran DSA Interview Prep gratis di CoddyKit. Ini adalah pelajaran 4 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 DSA Interview Prep, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus DSA Interview Prep mencakup 4 pelajaran total.

Masalah Cara Mendekode

Cara Mendekode (LeetCode 91) memetakan untaian digit ke huruf: 'A'=1, 'B'=2, ..., 'Z'=26. Dengan diberikan untaian digit berkode, hitung jumlah cara berbeda untuk mendekodenya. Sebagai contoh, '12' dapat didekode sebagai 'AB' (1+2) atau 'L' (12), sehingga ada 2 cara. '226' dapat menjadi 'BZ' (2+26), 'VF' (22+6), atau 'BBF' (2+2+6), sehingga ada 3 cara. Nol di awal membuat beberapa hasil dekode tidak valid.

# Encoding: A=1, B=2, ..., Z=26
# '12' → 'AB' or 'L' → 2 ways
# '226' → 'BZ' or 'VF' or 'BBF' → 3 ways
# '06' → invalid (no letter for '0')
# '10' → 'J' only → 1 way (only valid as 10, not 1+0)

s = '226'
print('Decodings for', s, ':', 3)  # Expected: 3

Formulasi DP untuk Cara Mendekode

Misalkan dp[i] = jumlah cara untuk mendekode s[:i]. Kasus dasar: dp[0] = 1 (untaian kosong, satu cara), dan dp[1] = 1 jika s[0] != '0', selain itu 0. Transisi: jika s[i-1] != '0', tambahkan dp[i-1] (dekode satu digit). Jika 10 ≤ int(s[i-2:i]) ≤ 26, tambahkan dp[i-2] (dekode dua digit). Ini pada dasarnya adalah pola Fibonacci dengan pemeriksaan validitas.

def num_decodings(s):
    n = len(s)
    dp = [0] * (n + 1)
    dp[0] = 1  # empty prefix
    dp[1] = 0 if s[0] == '0' else 1
    
    for i in range(2, n + 1):
        # Single digit decode
        if s[i-1] != '0':
            dp[i] += dp[i-1]
        # Two digit decode
        two_digit = int(s[i-2:i])
        if 10 <= two_digit <= 26:
            dp[i] += dp[i-2]
    return dp[n]

print(num_decodings('12'))   # 2
print(num_decodings('226'))  # 3
print(num_decodings('06'))   # 0

Jebakan Angka Nol di Awal

Bagian tersulit dari Cara Mendekode adalah menangani angka nol. '0' yang berdiri sendiri tidak dapat didekode (tidak ada huruf yang dipetakan ke 0), jadi jika s[i-1] == '0', jangan tambahkan dp[i-1]. '0' sebagai digit kedua hanya valid jika bilangan dua digitnya adalah 10 atau 20. '30' atau '40' (dan bilangan yang lebih besar) tidak valid karena melebihi 26. Selalu periksa 10 ≤ two_digit ≤ 26, bukan hanya two_digit ≤ 26.

def num_decodings(s):
    if not s or s[0] == '0': return 0
    n = len(s)
    dp = [0] * (n + 1)
    dp[0] = 1
    dp[1] = 1  # s[0] != '0' guaranteed by guard above
    for i in range(2, n + 1):
        one = int(s[i-1])
        two = int(s[i-2:i])
        if one != 0: dp[i] += dp[i-1]  # valid single digit
        if 10 <= two <= 26: dp[i] += dp[i-2]  # valid two digits
    return dp[n]

print(num_decodings('10'))   # 1 (only 'J')
print(num_decodings('30'))   # 0 (30 > 26, '0' alone invalid)
print(num_decodings('100'))  # 0 (dp[2]=1 then '00' invalid, single '0' invalid)

Cara Mendekode dengan Optimisasi Ruang

Seperti Fibonacci, relasi rekurensi jumlah cara mendekode hanya melihat dua posisi sebelumnya, sehingga Anda dapat mengurangi ruang O(n) menjadi O(1) dengan menggunakan dua variabel. Gunakan prev2 (dua langkah sebelumnya) dan prev1 (satu langkah sebelumnya). Pada setiap langkah, hitung curr dari keduanya, lalu geser nilainya. Ini identik dengan optimisasi Fibonacci menjadi dua variabel.

def num_decodings_o1(s):
    if not s or s[0] == '0': return 0
    prev2 = 1  # dp[0]
    prev1 = 1  # dp[1]
    for i in range(2, len(s) + 1):
        curr = 0
        if s[i-1] != '0':
            curr += prev1
        two = int(s[i-2:i])
        if 10 <= two <= 26:
            curr += prev2
        prev2, prev1 = prev1, curr
    return prev1

print(num_decodings_o1('226'))   # 3
print(num_decodings_o1('12'))    # 2
print(num_decodings_o1('0'))     # 0

Menghitung Jalur pada Tangga

Menaiki Tangga (LeetCode 70) menanyakan: ada berapa cara untuk menaiki n anak tangga jika Anda dapat melangkah 1 atau 2 anak tangga setiap kali? Ini persis merupakan barisan Fibonacci: ways(n) = ways(n-1) + ways(n-2). ways(1)=1, ways(2)=2, ways(3)=3, ways(4)=5. Pola ini dapat digeneralisasi jika Anda dapat melangkah hingga k anak tangga: ways(n) = sum(ways(n-1), ..., ways(n-k)).

def climb_stairs(n):
    if n <= 2: return n
    prev2, prev1 = 1, 2
    for _ in range(3, n + 1):
        prev2, prev1 = prev1, prev1 + prev2
    return prev1

for i in range(1, 8):
    print(f'climb_stairs({i}) = {climb_stairs(i)}')
# 1, 2, 3, 5, 8, 13, 21 — Fibonacci!

Menaiki Tangga dengan Langkah Bervariasi

Saat Anda dapat mengambil sejumlah langkah dari himpunan tertentu (misalnya, {1, 3, 5}), relasi rekurensinya menjadi dp[i] = sum(dp[i-k] for k in steps if i-k >= 0). Gunakan jendela geser berukuran max(steps) agar penggunaan memori efisien. Ini adalah varian penghitungan masalah ransel tak terbatas — setiap ukuran langkah dapat digunakan berkali-kali.

def count_ways(n, steps):
    dp = [0] * (n + 1)
    dp[0] = 1  # one way to stay at ground
    for i in range(1, n + 1):
        for step in steps:
            if i >= step:
                dp[i] += dp[i - step]
    return dp[n]

# Steps of 1 or 2 (classic climbing stairs)
print(count_ways(5, [1, 2]))    # 8
# Steps of 1, 3, or 5
print(count_ways(5, [1, 3, 5])) # 5
# Steps of 2 or 3
print(count_ways(6, [2, 3]))    # 3 (2+2+2, 3+3, 2+4-invalid, 2+2+2, 3+3, 3+2+1-no...)

Biaya Minimum untuk Menaiki Tangga

Biaya Minimum untuk Menaiki Tangga (LeetCode 746) memberikan biaya pada setiap anak tangga dan menanyakan biaya minimum untuk mencapai puncak. Dari anak tangga i, Anda dapat melompat ke i+1 atau i+2. Relasi rekurensinya adalah dp[i] = cost[i] + min(dp[i-1], dp[i-2]). Anda dapat mulai dari anak tangga 0 atau anak tangga 1. Jawabannya adalah min(dp[n-1], dp[n-2]).

def min_cost_climbing(cost):
    n = len(cost)
    if n == 1: return cost[0]
    dp = [0] * n
    dp[0] = cost[0]
    dp[1] = cost[1]
    for i in range(2, n):
        dp[i] = cost[i] + min(dp[i-1], dp[i-2])
    return min(dp[-1], dp[-2])  # can start from step 0 or 1

print(min_cost_climbing([10, 15, 20]))      # 15
print(min_cost_climbing([1, 100, 1, 1, 1, 100, 1, 1, 100, 1]))  # 6

Cara Mendekode II: Digit Pengganti

Cara Mendekode II (LeetCode 639) memperkenalkan karakter pengganti '*' yang dapat mewakili digit apa pun dari 1 hingga 9. Hal ini meningkatkan jumlah dekode yang valid secara drastis. Satu '*' menyumbang 9 cara (sebagai digit apa pun dari 1 hingga 9). Dua '*' secara bersamaan dapat membentuk 9×9 kombinasi dua digit, tetapi hanya kombinasi yang ≤ 26 yang valid (11-19 = 9 cara, 21-26 = 6 cara → 15 cara untuk '**'). Analisis kasus yang cermat diperlukan.

def num_decodings_ii(s):
    MOD = 10**9 + 7
    prev2, prev1 = 1, 9 if s[0] == '*' else (0 if s[0] == '0' else 1)
    for i in range(1, len(s)):
        curr = 0
        c, p = s[i], s[i-1]
        # Single digit
        if c == '*': curr += 9 * prev1
        elif c != '0': curr += prev1
        # Two digits
        if p == '*' and c == '*': curr += 15 * prev2  # 11-19(9) + 21-26(6)
        elif p == '*': curr += (2 if c <= '6' else 1) * prev2
        elif c == '*': curr += (9 if p == '1' else (6 if p == '2' else 0)) * prev2
        else:
            two = int(p + c)
            if 10 <= two <= 26: curr += prev2
        prev2, prev1 = prev1, curr % MOD
    return prev1 % MOD

print(num_decodings_ii('*'))   # 9
print(num_decodings_ii('1*'))  # 18

Kaitan dengan Fibonacci

Baik Cara Mendekode maupun Menaiki Tangga merupakan masalah dari keluarga Fibonacci yang disamarkan. Setiap DP yang dp[i]-nya hanya bergantung pada dp[i-1] dan dp[i-2] memiliki bentuk Fibonacci dan dapat diselesaikan dengan ruang O(1). Pemeriksaan validitas (digit nol, ukuran langkah) mengubah transisi mana yang aktif, tetapi tidak mengubah struktur dasar yang melihat dua posisi sebelumnya. Mengenali keluarga ini secara langsung merupakan pola berharga untuk bekerja cepat dalam wawancara.

# Fibonacci family: dp[i] = f(dp[i-1], dp[i-2])
# Fibonacci itself:        dp[i] = dp[i-1] + dp[i-2]
# Climbing stairs:         dp[i] = dp[i-1] + dp[i-2]
# Decode ways:             dp[i] = (dp[i-1] if one_valid) + (dp[i-2] if two_valid)
# Min cost stairs:         dp[i] = cost[i] + min(dp[i-1], dp[i-2])
# House robber:            dp[i] = max(dp[i-1], nums[i] + dp[i-2])

# All solved with 2 rolling variables:
prev2, prev1 = 0, 1
for _ in range(10):
    prev2, prev1 = prev1, prev1 + prev2
print('Fibonacci F(10):', prev1)  # 89

Menghitung Jalur pada Kisi

Masalah penghitungan terkait: diberikan kisi berukuran m×n, ada berapa jalur unik dari kiri atas ke kanan bawah jika Anda hanya dapat bergerak ke kanan atau ke bawah? Jawabannya adalah koefisien binomial C(m+n-2, m-1). Solusi DP mengisi tabel 2D dengan dp[i][j] = dp[i-1][j] + dp[i][j-1]. Ini merupakan versi 2D dari tangga Fibonacci — setiap sel adalah jumlah sel di atas dan di sebelah kirinya.

def unique_paths(m, n):
    dp = [[1] * n for _ in range(m)]
    for i in range(1, m):
        for j in range(1, n):
            dp[i][j] = dp[i-1][j] + dp[i][j-1]
    return dp[m-1][n-1]

# Or use math for O(1) solution
import math
def unique_paths_math(m, n):
    return math.comb(m + n - 2, m - 1)

print(unique_paths(3, 7))         # 28
print(unique_paths_math(3, 7))    # 28
print(unique_paths(3, 3))         # 6

Rangkuman Jebakan Wawancara

Kesalahan umum dalam Cara Mendekode: (1) Lupa bahwa '0' saja tidak valid — selalu periksa s[i-1] != '0' sebelum menambahkan dp[i-1]. (2) Menggunakan two_digit <= 26 tanpa memeriksa two_digit >= 10 — '07' tidak boleh didekode sebagai 'G'. (3) Mengembalikan dp[n-1], bukan dp[n] — tabel menggunakan indeks mulai dari 1 sehingga dp[n] sesuai dengan seluruh untaian. Selalu periksa kembali indeks larik saat tabel DP Anda memiliki satu elemen lebih banyak daripada masukan.

# Common bug: checking two_digit <= 26 without >= 10
def buggy_decode(s):
    dp = [0] * (len(s) + 1)
    dp[0] = dp[1] = 1
    for i in range(2, len(s) + 1):
        if s[i-1] != '0': dp[i] += dp[i-1]
        two = int(s[i-2:i])
        # BUG: '07' gives two=7, and 7 <= 26 would add dp[i-2]
        # Fix: require two >= 10
        if 10 <= two <= 26: dp[i] += dp[i-2]  # CORRECT
    return dp[len(s)]

print(buggy_decode('06'))   # 0 (correct, '0' alone invalid)
print(buggy_decode('07'))   # 0 (correct, '07' not valid, '0' alone invalid)
print(buggy_decode('27'))   # 1 (only 'BG', 27>26 so no two-digit)

Pemeriksaan Singkat

Uji pemahaman Anda tentang konsep Struktur Data & Algoritma — Persiapan Wawancara Pemrograman dari pelajaran ini.

Rangkuman Pelajaran

Dalam pelajaran ini Anda mempelajari: Cara Mendekode mengikuti relasi rekurensi yang mirip Fibonacci dengan pemeriksaan validitas untuk dekode satu digit (bukan nol) dan dua digit (10-26), Menaiki Tangga dan Tangga Berbiaya Minimum merupakan varian Fibonacci murni yang dapat diselesaikan dengan ruang O(1), dan mengenali keluarga Fibonacci yang melihat dua posisi sebelumnya dapat menghemat banyak waktu saat wawancara. Selanjutnya, kita akan mempelajari DP 2D dengan Jalur Unik dan Jumlah Jalur Minimum pada kisi.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Decode Ways dan Penghitungan Jalur” gratis?

Ya — teks lengkap “Decode Ways dan Penghitungan Jalur” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus DSA Interview Prep, upgrade ke CoddyKit PRO. Kursus DSA Interview Prep mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Decode Ways dan Penghitungan Jalur”?

Selesaikan decode-ways (pemetaan digit ke huruf) sebagai DP mirip Fibonacci, lalu hitung jalur pada tangga dengan ukuran langkah variabel. Kamu berlatih DSA 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 DSA Interview Prep?

Tidak diperlukan pengalaman sebelumnya. DSA 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 4 dari 4.

Berapa lama pelajaran “Decode Ways dan Penghitungan Jalur” 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 DSA Interview Prep ini?

Ya. Setiap pelajaran DSA 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. House Robber: Rekurensi Ambil atau Lewati
  2. Subarray Maksimum dan Subarray Produk Maksimum
  3. Word Break dan Segmentasi String
  4. Decode Ways dan Penghitungan Jalur
← Kembali ke DSA Interview Prep