【常用算法:查找篇】11.DFS与BFS核心原理及实战全解析
一、深度优先搜索(DFS):递归回溯的暴力美学
1. 核心思想与搜索状态树
- 核心逻辑:通过递归深入探索状态树,遇终点或死胡同则回溯,穷举所有可能路径。
- 状态树模型:以全排列为例,树的层级对应元素选择顺序,叶子节点为完整解。
根节点(无元素)/ | \1 2 3 (第1层选第1个元素)/ \ / \ / \2 3 1 3 1 2 (第2层选第2个元素)/ \/ \/ \3 2 2 1 (叶子节点:完整排列)
2. 经典问题与代码实现
全排列问题(无重复元素)
def permute(nums):n, result = len(nums), []used = [False] * ndef dfs(path):if len(path) == n:result.append(path.copy())returnfor i in range(n):if not used[i]:used[i] = Truepath.append(nums[i])dfs(path)path.pop()used[i] = Falsedfs([])return result
# 输出:[[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]
组合问题(C(n, m))
def combine(n, m):result, path = [], []def dfs(start, depth):if depth == m:result.append(path.copy())returnfor i in range(start, n+1):path.append(i)dfs(i+1, depth+1) # 剪枝:后续元素递增path.pop()dfs(1, 0)return result
# 示例:combine(4, 2) → [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
八皇后问题(位运算优化)
def solve_n_queens(n):col = [False] * nleft_diag = [False] * (2*n-1) # y-x + n-1right_diag = [False] * (2*n-1) # y+xresult = []def dfs(y, path):if y == n:result.append(path)returnfor x in range(n):if not col[x] and not left_diag[y-x+n-1] and not right_diag[y+x]:col[x] = left_diag[y-x+n-1] = right_diag[y+x] = Truedfs(y+1, path + [x])col[x] = left_diag[y-x+n-1] = right_diag[y+x] = Falsedfs(0, [])return result
# 输出:8皇后问题的92种解(以列坐标表示)
3. 剪枝策略
- 约束剪枝:如组合问题中强制递增选择,避免重复组合。
- 位运算压缩状态:八皇后问题用布尔数组标记列和对角线,O(1)时间判断合法性。
- 记忆化搜索:记录已访问状态,避免重复计算(如DFS判图环)。
二、广度优先搜索(BFS):分层扩展的最短路径神器
1. 核心思想与数据结构
- 核心逻辑:用队列实现逐层扩展,首次到达终点即最短路径(适用于无权图)。
- 关键组件:
- 队列(Queue):存储待探索节点,先进先出。
- 访问标记(visited):避免重复访问,O(1)查询。
- 父节点表(parent):路径还原,从终点回溯到起点。
2. 迷宫最短路径问题
Python代码实现
from collections import deque
def bfs_maze(maze, start, end):rows, cols = len(maze), len(maze[0])visited = [[False]*cols for _ in range(rows)]parent = {}queue = deque([start])visited[start[0]][start[1]] = Truedirections = [(-1,0),(1,0),(0,-1),(0,1)]while queue:x, y = queue.popleft()if (x, y) == end:# 路径还原path = []while (x, y) in parent:path.append((x, y))x, y = parent[(x, y)]return [start] + path[::-1]for dx, dy in directions:nx, ny = x+dx, y+dyif 0<=nx<rows and 0<=ny<cols and not visited[nx][ny] and maze[nx][ny]==0:visited[nx][ny] = Trueparent[(nx, ny)] = (x, y)queue.append((nx, ny))return None # 无解
优化:双向BFS
- 原理:从起点和终点同时搜索,相遇时终止,减少搜索层数。
- 适用场景:大规模迷宫(如105×105网格)。
3. 扩展:Dijkstra算法(带权图最短路径)
- 核心差异:用优先队列(堆)替代普通队列,每次选择当前最短距离节点扩展。
- 松弛操作:更新相邻节点距离,确保全局最优。
import heapq
def dijkstra(graph, start):dist = {node: float('inf') for node in graph}dist[start] = 0heap = [(0, start)]while heap:current_dist, u = heapq.heappop(heap)if current_dist > dist[u]:continuefor v, w in graph[u]:if dist[v] > dist[u] + w:dist[v] = dist[u] + wheapq.heappush(heap, (dist[v], v))return dist
三、DFS进阶:数独求解的剪枝艺术
1. 问题建模与约束
- 规则:行、列、宫(3×3)内数字1-9不重复。
- 状态表示:二维数组
board[9][9]
,0表示空白格。
2. 优化DFS实现
基础递归+回溯
def solve_sudoku(board):blanks = [(i,j) for i in range(9) for j in range(9) if board[i][j]==0]def is_valid(x, y, num):# 行、列、宫检查return not (num in board[x] or any(board[i][y]==num for i in range(9)) orany(board[i][j]==num for i in range((x//3)*3, (x//3+1)*3) for j in range((y//3)*3, (y//3+1)*3)))def dfs(index):if index == len(blanks):return Truex, y = blanks[index]for num in range(1, 10):if is_valid(x, y, num):board[x][y] = numif dfs(index+1):return Trueboard[x][y] = 0return Falsedfs(0)return board
位运算优化(O(1)合法性检查)
row_mask = [0]*9 # 行已用数字位掩码(每位代表1-9)
col_mask = [0]*9
box_mask = [0]*9 # 宫索引0-8for i in range(9):for j in range(9):num = board[i][j]if num != 0:bit = 1 << (num-1)row_mask[i] |= bitcol_mask[j] |= bitbox = (i//3)*3 + (j//3)box_mask[box] |= bitdef is_valid(x, y, num):bit = 1 << (num-1)box = (x//3)*3 + (y//3)return not (row_mask[x] & bit or col_mask[y] & bit or box_mask[box] & bit)
3. 启发式剪枝(MRV策略)
- 最少剩余值(MRV):优先填充可填数字最少的空白格,减少分支数。
blanks.sort(key=lambda pos: sum(1 for num in 1..9 if is_valid(*pos, num)))
四、总结:DFS vs BFS
特性 | DFS | BFS |
---|---|---|
核心数据结构 | 递归栈/显式栈 | 队列 |
路径性质 | 不一定最短(需遍历所有路径) | 首次到达即最短路径(无权图) |
适用场景 | 排列组合、约束满足问题(如数独) | 迷宫最短路径、层序遍历、社交网络 |
时间复杂度 | O(分支数^深度)(依赖剪枝) | O(节点数) |
空间复杂度 | O(深度)(递归栈) | O(节点数) |
🔥 终极算法武器库,助你突破编程思维瓶颈!
从排列组合到复杂约束问题,从无权图到带权图,掌握DFS与BFS核心逻辑,轻松驾驭算法面试与工程实践!🚀