أنماط الخوارزميات: الأنماط الـ 15 الأساسية

DFS و BFS والتراجع

4 دقيقة للقراءة

هذه الأنماط هي مجموعة أدواتك لاستكشاف الأشجار والرسوم البيانية وتوليد جميع التوافيق الممكنة. تظهر في مجموعة واسعة من مسائل المقابلات.

DFS (البحث بالعمق أولاً)

DFS يستكشف بأعمق ما يمكن قبل التراجع. يستخدم مكدسًا (أو مكدس الاستدعاءات في التكرار).

متى تستخدم DFS:

  • اجتيازات الأشجار (preorder, inorder, postorder)
  • إيجاد المسارات في الرسوم البيانية
  • المكونات المتصلة
  • كشف الدورات
# عدد الجزر (DFS كلاسيكي)
def num_islands(grid):
    if not grid:
        return 0
    rows, cols = len(grid), len(grid[0])
    count = 0

    def dfs(r, c):
        if r < 0 or r >= rows or c < 0 or c >= cols or grid[r][c] == '0':
            return
        grid[r][c] = '0'  # تحديد كمزار
        dfs(r+1, c)
        dfs(r-1, c)
        dfs(r, c+1)
        dfs(r, c-1)

    for r in range(rows):
        for c in range(cols):
            if grid[r][c] == '1':
                dfs(r, c)
                count += 1
    return count

# مجموع المسار في شجرة ثنائية
def has_path_sum(root, target_sum):
    if not root:
        return False
    if not root.left and not root.right:
        return root.val == target_sum
    return (has_path_sum(root.left, target_sum - root.val) or
            has_path_sum(root.right, target_sum - root.val))

BFS (البحث بالعرض أولاً)

BFS يستكشف مستوى بمستوى باستخدام طابور. يضمن أقصر مسار في الرسوم البيانية غير الموزونة.

متى تستخدم BFS:

  • أقصر مسار (رسم بياني غير موزون)
  • الاجتياز مستوى بمستوى
  • مسائل الحد الأدنى من الخطوات/الحركات
  • البحث عن أقرب جار
from collections import deque

# أقصر مسار في مصفوفة ثنائية
def shortest_path(grid):
    n = len(grid)
    if grid[0][0] == 1 or grid[n-1][n-1] == 1:
        return -1

    queue = deque([(0, 0, 1)])  # (صف، عمود، مسافة)
    visited = {(0, 0)}
    directions = [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]

    while queue:
        r, c, dist = queue.popleft()
        if r == n-1 and c == n-1:
            return dist
        for dr, dc in directions:
            nr, nc = r + dr, c + dc
            if 0 <= nr < n and 0 <= nc < n and grid[nr][nc] == 0 and (nr, nc) not in visited:
                visited.add((nr, nc))
                queue.append((nr, nc, dist + 1))
    return -1

متى تختار DFS ومتى BFS

المعيار DFS BFS
أقصر مسار لا (بشكل عام) نعم (غير موزون)
استخدام الذاكرة O(h) الارتفاع O(w) العرض
التطبيق تكرار أو مكدس طابور
الأفضل للأشجار مسائل المسارات الاجتياز مستوى بمستوى
الأفضل للرسوم البيانية المكونات المتصلة أقصر مسافة

التراجع (Backtracking)

التراجع هو DFS مع لمسة: تبني حلاً تدريجيًا وتتخلى عنه ("تتراجع") عندما لا يمكن أن يؤدي لنتيجة صحيحة.

القالب:

def backtrack(candidates, path, result, start):
    if is_valid_solution(path):
        result.append(path[:])  # أضف نسخة
        return
    for i in range(start, len(candidates)):
        path.append(candidates[i])       # اختر
        backtrack(candidates, path, result, i + 1)  # استكشف
        path.pop()                        # ألغِ الاختيار (تراجع)

مسائل التراجع الكلاسيكية:

# المجموعات الفرعية: توليد جميع المجموعات الفرعية
def subsets(nums):
    result = []
    def backtrack(start, path):
        result.append(path[:])
        for i in range(start, len(nums)):
            path.append(nums[i])
            backtrack(i + 1, path)
            path.pop()
    backtrack(0, [])
    return result

# التباديل
def permutations(nums):
    result = []
    def backtrack(path, remaining):
        if not remaining:
            result.append(path[:])
            return
        for i in range(len(remaining)):
            path.append(remaining[i])
            backtrack(path, remaining[:i] + remaining[i+1:])
            path.pop()
    backtrack([], nums)
    return result

# N-Queens (الملكات الثمانية)
def solve_n_queens(n):
    result = []
    def backtrack(row, cols, diag1, diag2, board):
        if row == n:
            result.append([''.join(r) for r in board])
            return
        for col in range(n):
            if col in cols or (row-col) in diag1 or (row+col) in diag2:
                continue
            board[row][col] = 'Q'
            backtrack(row+1, cols|{col}, diag1|{row-col}, diag2|{row+col}, board)
            board[row][col] = '.'
    board = [['.']*n for _ in range(n)]
    backtrack(0, set(), set(), set(), board)
    return result

نصيحة للمقابلات: مسائل التراجع تتبع نمط "اختر، استكشف، ألغِ الاختيار". إذا تعرفت على هذا الهيكل، الحل يكتب نفسه.


التالي: النمط الذي يخيف معظم المرشحين: البرمجة الديناميكية. :::

اختبار

اختبار الوحدة 3: أنماط الخوارزميات

خذ الاختبار