BFS: En Kısa Yol ve Seviye Dolaşımı
Ağırlıksız bir grafta en kısa yolu bulmak için BFS kullanın, sözcük merdiveni problemini seviye seviye çözün ve karma haritasıyla bir grafın kopyasını oluşturun.
BFS: En Kısa Yol ve Seviye Dolaşımı, CoddyKit'te ücretsiz bir Coding Interview Prep dersidir. Bu, 4 dersinin 2. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, Coding Interview Prep öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Coding Interview Prep kursu toplamda 4 dersten oluşur.
Ağırlıksız Graflarda BFS ve En Kısa Yol
BFS, düğümleri kaynaktan artan uzaklık sırasıyla keşfettiği için ağırlıksız bir grafta en kısa yolu (en az kenarı) bulur. BFS sırasında bir düğüme ilk kez ulaşıldığında, bu ulaşım mümkün olan en kısa yol üzerinden gerçekleşmiştir. Bu özellik DFS için geçerli değildir. Negatif olmayan ağırlıklara sahip ağırlıklı graflar için bunun yerine Dijkstra algoritmasını kullanın; BFS, tüm kenarların ağırlığını örtük olarak 1 kabul eder.
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)Gerçek En Kısa Yolu Takip Etme
Yalnızca uzunluğu değil, gerçek yolu da yeniden oluşturmak için her düğüme nasıl ulaşıldığını kaydeden bir ebeveyn sözlüğü tutun. Hedefe ulaştığınızda, sonuçta başlangıçtan sona doğru ilerlemek için ebeveyn eşlemesinde sondan başlayarak geriye doğru iz sürün ve sonucu ters çevirin. Bu yöntem ebeveyn eşlemesi için O(V) alan ekler; ancak BFS tamamlandıktan sonra tam yolu O(yol_uzunluğu) sürede sağlar.
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]Kelime Merdiveni: Örtük Graf Üzerinde BFS
Kelime Merdiveni (LeetCode #127), her ara kelimenin bir sözlükte bulunması koşuluyla başlangıç kelimesini bitiş kelimesine dönüştürmek için gereken tek karakterlik değişikliklerin minimum sayısını bulmayı ister. Bu, düğümlerin kelimelerden oluştuğu ve bir harf farklılık gösteren kelimeleri kenarların bağladığı bir örtük graf üzerinde BFS uygulamasıdır. Tüm tek harfli değişimleri üretin ve bunların kelime kümesinde bulunup bulunmadığını kontrol edin. BFS, minimum dönüşüm dizisini garanti eder.
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'])) # 5Seviye Dolaşımı: Uzaklığı Takip Etme
Seviye dolaşımı, düğümleri kaynaktan olan uzaklıklarına göre gruplar; bu, seviye başına işlem yapılması gereken sorular için doğrudan kullanışlıdır. Uzaklığı ya kuyruk öğesinde (node, dist) demeti olarak saklayarak ya da kuyruk boyutu tekniğini kullanarak takip edin (her seviyeden önce kuyruk boyutunu kaydedin, tam olarak bu sayıda düğümü işleyin, ardından seviye sayacını artırın). Her iki yaklaşım da aynı sonuçları verir.
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}Grafı Klonlama
Grafı Klonlama (LeetCode #133), bağlantılı yönsüz bir grafın derin kopyasını oluşturur. BFS ve özgün düğümleri kopyalarıyla eşleyen bir karma eşleme kullanın. Bir düğümü ilk kez ziyaret ettiğinizde kopyasını oluşturun ve eşlemeye ekleyin. Komşuları işlerken kopyalarını arayın veya oluşturun ve kenarları bağlayın. Karma eşleme iki amaca hizmet eder: ziyaret edilen düğümleri takip etmek ve özgün düğümleri kopyalarıyla eşlemek.
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]Çift Yönlü BFS
Çift yönlü BFS, BFS'yi aynı anda hem kaynaktan hem de hedeften başlatır ve her uçtan bir seviye genişletir. İki ön sınır karşılaştığında en kısa yolu bulmuş olursunuz. Büyük graflarda bu yaklaşım, arama alanını b dallanma katsayısı ve d yol uzunluğu olmak üzere O(b^d) değerinden O(2 * b^(d/2)) değerine düşürür. Bu, büyük sözlüklere sahip kelime merdiveni gibi derin biçimde bağlantılı graflarda çarpıcı bir iyileşmedir.
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'])) # 5Ağırlıklı Graflar için 0-1 BFS
0-1 BFS, kenar ağırlıklarının yalnızca 0 veya 1 olduğu grafları işler. Normal bir kuyruk yerine bir çift uçlu kuyruk kullanın: ağırlığı 1 olan kenarlar için (sonraki seviye) arkaya, ağırlığı 0 olan kenarlar için (aynı seviye) öne ekleyin. Bu, ikili ağırlıklarda Dijkstra'nın O((V+E) log V) süresinden daha hızlı olan O(V + E) süreli en kısa yol hesaplaması sağlar. Bazı hamlelerin ücretsiz, diğerlerinin ise 1 maliyetli olduğu ızgara sorularında yaygın olarak kullanılır.
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]Duvarlar ve Kapılar (Çok Kaynaklı BFS)
Duvarlar ve Kapılar, her boş odayı en yakın kapıya olan uzaklıkla doldurur. Çok kaynaklı BFS kullanın: kuyruğu aynı anda tüm kapılarla (0 değeriyle) başlatın ve dışa doğru genişletin. Her hücrenin değeri, hücreye ilk kez ulaşıldığı seviyeye ayarlanır. Bu O(mn) çözüm, her boş odadan ayrı ayrı BFS çalıştırmaktan daha verimlidir; ikinci yaklaşımın maliyeti O(m²n²) olur.
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, 2Yılanlar ve Merdivenler BFS'si
Yılanlar ve Merdivenler (LeetCode #909), numaralı bir ızgara üzerinde en kısa yol bulma problemidir. Tahtayı, herhangi bir kareden 1-6 arasında zar atabildiğiniz ve indiğiniz karedeki yılanın veya merdivenin sizi başka bir konuma ışınlayabildiği ağırlıksız bir graf olarak modelleyin. BFS, minimum zar atışı sayısını bulur. Temel zorluk, satır yönünün dönüşümlü olduğu düzende, tek boyutlu konum ile iki boyutlu tahta koordinatları arasındaki dönüşümü doğru yapmaktır.
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')BFS Karmaşıklığı ve İyileştirmeler
BFS'nin zaman karmaşıklığı O(V + E) değeridir; çünkü her köşe kuyruğa bir kez eklenir ve her kenar sabit sayıda incelenir. Alan karmaşıklığı, ziyaret edilenler kümesi ve kuyruk için O(V) değeridir. Izgara graflarında V = m*n ve E = 4*m*n'dir (her hücrenin 4 komşusu vardır); dolayısıyla bir ızgarada BFS O(mn) sürede çalışır. Temel iyileştirme: ziyaret edilenleri takip etmek için liste (O(n) arama) yerine küme (O(1) arama) kullanın. Ziyaret edildi olarak kuyruktan çıkarırken değil, kuyruğa eklerken işaretleyin.
# 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')İkili Matriste En Yakın 0
01 Matrisi (LeetCode #542), her hücrenin en yakın 0'a olan uzaklığını bulur. Tüm 0'lardan aynı anda başlatılan çok kaynaklı BFS, en uygun O(mn) çözümü sağlar. Kuyruğu uzaklığı 0 olan tüm 0 hücreleriyle başlatın ve tüm 1 hücrelerinin uzaklığını sonsuz olarak ayarlayın. BFS, uzaklıkları 0'lardan dışa doğru yayar ve her 1 hücresinin uzaklığını, hücreye ilk kez ulaşıldığında belirler; bu uzaklığın en kısa olduğu garanti edilir.
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]]Hızlı Kontrol
Bu dersteki Veri Yapıları ve Algoritmalar — Kodlama Mülakatı Hazırlığı kavramlarını anlayışınızı test edin.
Ders Özeti
Bu derste şunları öğrendiniz: rotayı yeniden oluşturmak için ebeveyn takibiyle ağırlıksız graflarda en kısa yol bulma için BFS'yi, örtük bir graf üzerinde temel bir BFS uygulaması olarak kelime merdivenini, büyük graflar için çift yönlü BFS'yi ve birden çok başlangıç noktası içeren sorular için çok kaynaklı BFS'yi. Sırada, bağlantılı bileşenler ve boya doldurma için DFS'yi uygulayacağız.
Yapay zeka eğitmeniyle Coding Interview Prep öğren — ücretsiz
Tarayıcında gerçek kod yaz ve çalıştır, 7/24 yapay zeka eğitmeninden anında yardım al; web'de ya da uygulamada kaldığın yerden devam et.
- Kurslar
- 90
- Dersler
- 360
Sıkça Sorulan Sorular
“BFS: En Kısa Yol ve Seviye Dolaşımı” dersi ücretsiz mi?
Evet — “BFS: En Kısa Yol ve Seviye Dolaşımı” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve Coding Interview Prep kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Coding Interview Prep kursu toplamda 4 dersten oluşur.
“BFS: En Kısa Yol ve Seviye Dolaşımı” dersinde ne öğreneceğim?
Ağırlıksız bir grafta en kısa yolu bulmak için BFS kullanın, sözcük merdiveni problemini seviye seviye çözün ve karma haritasıyla bir grafın kopyasını oluşturun. Coding Interview Prep ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
Coding Interview Prep öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te Coding Interview Prep, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 2. dersidir.
“BFS: En Kısa Yol ve Seviye Dolaşımı” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu Coding Interview Prep dersinde kod yazıp çalıştırabilir miyim?
Evet. Her Coding Interview Prep dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- Graf Gösterimleri ve Dolaşım Kurulumu
- BFS: En Kısa Yol ve Seviye Dolaşımı
- DFS: Bağlı Bileşenler ve Alan Doldurma
- Yönlü ve Yönsüz Graflarda Döngü Algılama