0Pricing
DSA Interview Prep · Pelajaran

BFS: Jalur Terpendek dan Traversal Level

Gunakan BFS untuk menemukan jalur terpendek dalam graf tak berbobot, selesaikan word-ladder per level, dan kloning graf menggunakan hash map.

BFS: Jalur Terpendek dan Traversal Level adalah pelajaran DSA Interview Prep gratis di CoddyKit. Ini adalah pelajaran 2 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.

BFS dan Jalur Terpendek pada Graf Tak Berbobot

BFS menemukan jalur terpendek (jumlah sisi paling sedikit) dalam graf tak berbobot karena menjelajahi simpul berdasarkan jarak yang meningkat dari sumber. Saat sebuah simpul pertama kali dicapai selama BFS, simpul tersebut dicapai melalui jalur yang paling pendek. Sifat ini tidak berlaku untuk DFS. Untuk graf berbobot dengan bobot non-negatif, gunakan algoritma Dijkstra—BFS secara implisit menganggap semua sisi memiliki bobot 1.

from collections import deque, defaultdict

def shortest_path(graph, start, end):
    if start == end:
        return 0
    visited = {start}
    queue = deque([(start, 0)])  # (node, distance)
    while queue:
        node, dist = queue.popleft()
        for neighbour in graph[node]:
            if neighbour == end:
                return dist + 1
            if neighbour not in visited:
                visited.add(neighbour)
                queue.append((neighbour, dist + 1))
    return -1  # no path found

graph = defaultdict(list)
for u, v in [(0,1),(1,2),(2,3),(0,3),(1,4)]:
    graph[u].append(v); graph[v].append(u)
print(shortest_path(graph, 0, 3))  # 1 (direct edge)
print(shortest_path(graph, 0, 4))  # 2 (0->1->4)

Melacak Jalur Terpendek yang Sebenarnya

Untuk merekonstruksi jalur yang sebenarnya (bukan hanya panjangnya), pertahankan kamus induk yang mencatat cara setiap simpul dicapai. Saat mencapai tujuan, telusuri kembali pemetaan induk dari akhir ke awal, lalu balik hasilnya. Cara ini menambahkan ruang O(V) untuk pemetaan induk, tetapi menyediakan jalur lengkap dalam waktu O(panjang_jalur) setelah BFS selesai.

from collections import deque, defaultdict

def shortest_path_with_route(graph, start, end):
    parent = {start: None}
    queue = deque([start])
    while queue:
        node = queue.popleft()
        if node == end:
            break
        for nb in graph[node]:
            if nb not in parent:
                parent[nb] = node
                queue.append(nb)
    if end not in parent:
        return []  # no path
    # Reconstruct path by tracing back
    path = []
    node = end
    while node is not None:
        path.append(node)
        node = parent[node]
    return path[::-1]  # reverse

graph = defaultdict(list)
for u, v in [(0,1),(1,2),(2,3),(0,4),(4,3)]:
    graph[u].append(v); graph[v].append(u)
print(shortest_path_with_route(graph, 0, 3))  # [0, 4, 3] or [0, 1, 2, 3]

Tangga Kata: BFS pada Graf Implisit

Tangga Kata (LeetCode #127) meminta jumlah minimum perubahan satu karakter untuk mengubah kata awal menjadi kata akhir, dengan syarat setiap kata perantara harus ada dalam kamus. Ini adalah BFS pada graf implisit, dengan simpul berupa kata dan sisi yang menghubungkan kata-kata yang berbeda satu huruf. Hasilkan semua mutasi satu huruf dan periksa apakah mutasi tersebut ada dalam himpunan kata. BFS menjamin urutan transformasi minimum.

from collections import deque

def word_ladder(begin_word, end_word, word_list):
    word_set = set(word_list)
    if end_word not in word_set:
        return 0
    queue = deque([(begin_word, 1)])
    visited = {begin_word}
    while queue:
        word, steps = queue.popleft()
        for i in range(len(word)):
            for c in 'abcdefghijklmnopqrstuvwxyz':
                new_word = word[:i] + c + word[i+1:]
                if new_word == end_word:
                    return steps + 1
                if new_word in word_set and new_word not in visited:
                    visited.add(new_word)
                    queue.append((new_word, steps + 1))
    return 0

print(word_ladder('hit', 'cog', ['hot','dot','dog','lot','log','cog']))  # 5

Penelusuran per Level: Melacak Jarak

Penelusuran per level mengelompokkan simpul berdasarkan jaraknya dari sumber, yang sangat berguna untuk soal yang memerlukan pemrosesan per level. Lacak jarak dengan menyimpannya dalam elemen antrean sebagai tupel (node, dist), atau gunakan teknik ukuran antrean (catat ukuran antrean sebelum setiap level, proses tepat sejumlah simpul tersebut, lalu tambah penghitung level). Kedua pendekatan menghasilkan hasil yang sama.

from collections import deque, defaultdict

def bfs_levels(graph, start):
    levels = {}
    visited = {start}
    queue = deque([start])
    dist = 0
    while queue:
        # Process all nodes at current distance
        for _ in range(len(queue)):
            node = queue.popleft()
            levels[node] = dist
            for nb in graph[node]:
                if nb not in visited:
                    visited.add(nb)
                    queue.append(nb)
        dist += 1
    return levels

graph = defaultdict(list)
for u, v in [(0,1),(0,2),(1,3),(2,3),(3,4)]:
    graph[u].append(v); graph[v].append(u)
print(bfs_levels(graph, 0))  # {0:0, 1:1, 2:1, 3:2, 4:3}

Klon Graf

Klon Graf (LeetCode #133) membuat salinan mendalam dari graf tak berarah yang terhubung. Gunakan BFS dan peta pencincangan yang memetakan simpul asli ke klonnya. Saat pertama kali mengunjungi sebuah simpul, buat klonnya dan tambahkan ke peta. Saat memproses tetangga, cari atau buat klon mereka, lalu hubungkan sisi-sisinya. Peta pencincangan memiliki dua fungsi: melacak simpul yang telah dikunjungi dan memetakan simpul asli ke salinannya.

from collections import deque

class Node:
    def __init__(self, val=0, neighbors=None):
        self.val = val
        self.neighbors = neighbors if neighbors is not None else []

def clone_graph(node):
    if not node:
        return None
    old_to_new = {node: Node(node.val)}
    queue = deque([node])
    while queue:
        curr = queue.popleft()
        for nb in curr.neighbors:
            if nb not in old_to_new:
                old_to_new[nb] = Node(nb.val)
                queue.append(nb)
            old_to_new[curr].neighbors.append(old_to_new[nb])
    return old_to_new[node]

# Build a simple graph: 1 -- 2 -- 3 -- 4 -- 1
n1 = Node(1); n2 = Node(2); n3 = Node(3); n4 = Node(4)
n1.neighbors = [n2, n4]; n2.neighbors = [n1, n3]
n3.neighbors = [n2, n4]; n4.neighbors = [n3, n1]
cloned = clone_graph(n1)
print(cloned.val, [n.val for n in cloned.neighbors])  # 1 [2, 4]

BFS Dua Arah

BFS dua arah memulai BFS dari sumber dan tujuan secara bersamaan, dengan memperluas satu level setiap kali dari kedua ujung. Saat kedua batas pencarian bertemu, Anda telah menemukan jalur terpendek. Untuk graf besar, pendekatan ini mengurangi ruang pencarian dari O(b^d) menjadi O(2 * b^(d/2)), dengan b sebagai faktor percabangan dan d sebagai panjang jalur—peningkatan yang sangat besar untuk graf dengan konektivitas tinggi seperti Tangga Kata dengan kamus besar.

from collections import defaultdict

def word_ladder_bidir(begin, end, word_list):
    word_set = set(word_list)
    if end not in word_set:
        return 0
    front, back = {begin}, {end}
    visited = {begin, end}
    steps = 1
    while front and back:
        # Always expand the smaller frontier
        if len(front) > len(back):
            front, back = back, front
        next_front = set()
        for word in front:
            for i in range(len(word)):
                for c in 'abcdefghijklmnopqrstuvwxyz':
                    nw = word[:i] + c + word[i+1:]
                    if nw in back:  # frontiers met!
                        return steps + 1
                    if nw in word_set and nw not in visited:
                        visited.add(nw)
                        next_front.add(nw)
        front = next_front
        steps += 1
    return 0

print(word_ladder_bidir('hit','cog',['hot','dot','dog','lot','log','cog']))  # 5

BFS 0-1 untuk Graf Berbobot

BFS 0-1 menangani graf yang bobot sisinya hanya 0 atau 1. Alih-alih menggunakan antrean biasa, gunakan antrean berujung ganda: gunakan append di bagian belakang untuk sisi berbobot 1 (level berikutnya) dan di bagian depan untuk sisi berbobot 0 (level yang sama). Cara ini menghasilkan perhitungan jalur terpendek dalam O(V + E)—lebih cepat daripada O((V+E) log V) milik Dijkstra ketika bobotnya biner. Pendekatan ini umum digunakan dalam soal kisi ketika beberapa perpindahan gratis dan perpindahan lainnya berbiaya 1.

from collections import deque

def zero_one_bfs(graph, start, n):
    # graph: list of (neighbour, weight) where weight is 0 or 1
    dist = [float('inf')] * n
    dist[start] = 0
    dq = deque([start])
    while dq:
        node = dq.popleft()
        for nb, w in graph[node]:
            if dist[node] + w < dist[nb]:
                dist[nb] = dist[node] + w
                if w == 0:
                    dq.appendleft(nb)   # same level
                else:
                    dq.append(nb)       # next level
    return dist

# Simple test:
graph = [[(1, 0), (2, 1)],   # node 0: free to 1, cost 1 to 2
         [(3, 1)],            # node 1: cost 1 to 3
         [(3, 0)],            # node 2: free to 3
         []]
print(zero_one_bfs(graph, 0, 4))  # [0, 0, 1, 1]

Dinding dan Gerbang (BFS Multi-Sumber)

Dinding dan Gerbang mengisi setiap ruangan kosong dengan jarak ke gerbang terdekatnya. Gunakan BFS multi-sumber: inisialisasi antrean secara bersamaan dengan semua gerbang (bernilai 0), lalu perluas pencarian ke arah luar. Nilai setiap sel ditetapkan berdasarkan level saat sel tersebut pertama kali dicapai. Solusi O(mn) ini lebih efisien daripada menjalankan BFS secara terpisah dari setiap ruangan kosong, yang akan membutuhkan O(m²n²).

from collections import deque

def walls_and_gates(rooms):
    if not rooms:
        return
    rows, cols = len(rooms), len(rooms[0])
    INF = float('inf')
    queue = deque()
    # Multi-source: all gates at distance 0
    for r in range(rows):
        for c in range(cols):
            if rooms[r][c] == 0:  # gate
                queue.append((r, c))
    dirs = [(0,1),(0,-1),(1,0),(-1,0)]
    while queue:
        r, c = queue.popleft()
        for dr, dc in dirs:
            nr, nc = r+dr, c+dc
            if 0<=nr<rows and 0<=nc<cols and rooms[nr][nc]==INF:
                rooms[nr][nc] = rooms[r][c] + 1
                queue.append((nr, nc))

rooms = [[float('inf'),-1,0,float('inf')],
         [float('inf'),float('inf'),float('inf'),-1],
         [float('inf'),-1,float('inf'),-1],
         [0,-1,float('inf'),float('inf')]]
walls_and_gates(rooms)
print(rooms[0][0], rooms[1][1])  # 3, 2

BFS Ular dan Tangga

Ular dan Tangga (LeetCode #909) adalah soal jalur terpendek dengan BFS pada kisi bernomor. Modelkan papan sebagai graf tak berbobot, dengan kemungkinan bergerak 1–6 langkah dari setiap kotak dan mendarat pada ular atau tangga yang memindahkan Anda secara teleportasi. BFS menemukan jumlah lemparan dadu minimum. Tantangan utamanya adalah mengonversi posisi 1D menjadi koordinat papan 2D, dengan memperhitungkan tata letak yang arah barisnya bergantian.

from collections import deque

def snakes_and_ladders(board):
    n = len(board)
    def get_board(pos):
        r, c = divmod(pos - 1, n)
        if r % 2 == 1: c = n - 1 - c  # alternating direction
        return board[n - 1 - r][c]

    visited = {1}
    queue = deque([(1, 0)])
    while queue:
        pos, moves = queue.popleft()
        for dice in range(1, 7):
            next_pos = pos + dice
            if next_pos > n * n:
                break
            val = get_board(next_pos)
            if val != -1:
                next_pos = val  # snake or ladder
            if next_pos == n * n:
                return moves + 1
            if next_pos not in visited:
                visited.add(next_pos)
                queue.append((next_pos, moves + 1))
    return -1

print('BFS models game as an unweighted shortest-path problem')

Kompleksitas dan Optimasi BFS

Kompleksitas waktu BFS adalah O(V + E) karena setiap simpul dimasukkan ke antrean satu kali dan setiap sisi diperiksa sejumlah konstan kali. Kompleksitas ruangnya adalah O(V) untuk himpunan yang telah dikunjungi dan antrean. Untuk graf kisi, V = m*n dan E = 4*m*n (setiap sel memiliki 4 tetangga), sehingga BFS pada kisi adalah O(mn). Optimasi utama: gunakan himpunan untuk pencarian O(1), bukan daftar untuk pencarian O(n). Tandai sel sebagai telah dikunjungi saat memasukkannya ke antrean, bukan saat mengeluarkannya.

# BFS on a graph with V vertices and E edges:
# Time:  O(V + E) -- each vertex and edge visited once
# Space: O(V)     -- visited set + queue

# BFS on an m x n grid:
# V = m*n cells
# E <= 4*m*n edges (4 directions, max)
# Time:  O(m*n)
# Space: O(m*n)

# Common pitfalls:
# 1. Marking visited on dequeue (not enqueue) -> same node queued multiple times
# 2. Using a list for visited -> O(n) membership check -> O(V*E) total
# 3. Not handling disconnected graph -> BFS from single source misses components
print('O(V+E) time, O(V) space -- mark visited on enqueue')

Nol Terdekat dalam Matriks Biner

Matriks 01 (LeetCode #542) menemukan jarak dari setiap sel ke 0 terdekat. BFS multi-sumber dari semua 0 secara bersamaan memberikan solusi optimal O(mn). Inisialisasi antrean dengan semua sel 0 pada jarak 0 dan semua sel 1 pada jarak tak terhingga. BFS menyebarkan jarak ke luar dari sel-sel 0, dengan menetapkan jarak setiap sel 1 saat pertama kali dicapai (yang dijamin merupakan jarak terpendek).

from collections import deque

def update_matrix(mat):
    rows, cols = len(mat), len(mat[0])
    dist = [[float('inf')] * cols for _ in range(rows)]
    queue = deque()
    for r in range(rows):
        for c in range(cols):
            if mat[r][c] == 0:
                dist[r][c] = 0
                queue.append((r, c))
    dirs = [(0,1),(0,-1),(1,0),(-1,0)]
    while queue:
        r, c = queue.popleft()
        for dr, dc in dirs:
            nr, nc = r+dr, c+dc
            if 0<=nr<rows and 0<=nc<cols:
                if dist[r][c] + 1 < dist[nr][nc]:
                    dist[nr][nc] = dist[r][c] + 1
                    queue.append((nr, nc))
    return dist

mat = [[0,0,0],[0,1,0],[1,1,1]]
result = update_matrix(mat)
for row in result: print(row)  # [[0,0,0],[0,1,0],[1,2,1]]

Pemeriksaan Singkat

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

Ringkasan Pelajaran

Dalam pelajaran ini Anda mempelajari: BFS untuk jalur terpendek dalam graf tak berbobot dengan pelacakan induk untuk merekonstruksi rute, Tangga Kata sebagai contoh BFS kanonis pada graf implisit, BFS dua arah untuk graf besar, dan BFS multi-sumber untuk soal dengan beberapa titik awal. Selanjutnya, kita menerapkan DFS pada komponen terhubung dan pengisian area.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “BFS: Jalur Terpendek dan Traversal Level” gratis?

Ya — teks lengkap “BFS: Jalur Terpendek dan Traversal Level” 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 “BFS: Jalur Terpendek dan Traversal Level”?

Gunakan BFS untuk menemukan jalur terpendek dalam graf tak berbobot, selesaikan word-ladder per level, dan kloning graf menggunakan hash map. 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 2 dari 4.

Berapa lama pelajaran “BFS: Jalur Terpendek dan Traversal Level” 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. Representasi Graf dan Persiapan Traversal
  2. BFS: Jalur Terpendek dan Traversal Level
  3. DFS: Komponen Terhubung dan Flood Fill
  4. Deteksi Siklus pada Graf Berarah dan Tak Berarah
← Kembali ke DSA Interview Prep