组合问题,切割问题,子集问题,排列问题,棋盘问题,每一种问题都是回溯的应用,回溯伴随着递归,同时也是深度优先搜索的应用,具体到每一道题目,涉及到如何剪枝,如何去重,如何设置终止条件,如何在for循环里面控制搜索范围等,都是需要关注的
332、重新安排行程
class Solution:
def findItinerary(self, tickets):
from collections import defaultdict
targets = defaultdict(list) # 创建默认字典,用于存储机场映射关系
for ticket in tickets:
targets[ticket[0]].append(ticket[1]) # 将机票输入到字典中
for key in targets:
targets[key].sort(reverse=True) # 对到达机场列表进行字母逆序排序
result = []
self.backtracking("JFK", targets, result) # 调用回溯函数开始搜索路径
return result[::-1] # 返回逆序的行程路径
def backtracking(self, airport, targets, result):
while targets[airport]: # 当机场还有可到达的机场时
next_airport = targets[airport].pop() # 弹出下一个机场
self.backtracking(next_airport, targets, result) # 递归调用回溯函数进行深度优先搜索
result.append(airport) # 将当前机场添加到行程路径中
Python使用回溯算法只有逆序字典可以AC,数组及字典法会卡在最后一个用例上超时
51、N皇后:
class Solution(object):
def backtracking(self, n, row, path, res):
if row == n:
res.append(path[:])
return
for col in range(n):
if self.is_valid(row, col, n, path):
path[row] = path[row][:col]+'Q'+path[row][col+1:]
self.backtracking(n, row+1, path, res)
path[row] = path[row][:col]+'.'+path[row][col+1:]
def is_valid(self, row, col, n, path):
for i in range(row):
if path[i][col] == 'Q':
return False
i, j = row-1, col-1
while i >= 0 and j >= 0:
if path[i][j] == 'Q':
return False
i -= 1
j -= 1
i, j = row-1, col+1
while i >= 0 and j < n:
if path[i][j] == 'Q':
return False
i -= 1
j += 1
return True
def solveNQueens(self, n):
"""
:type n: int
:rtype: List[List[str]]
"""
res = []
path = ['.'*n for _ in range(n)]
self.backtracking(n, 0, path, res)
return res
解决N皇后问题,使用row控制递归深度,使用col控制for循环遍历集合的宽度,选取容器有技巧
37、解数独:
class Solution(object):
def backtracking(self, board):
for i in range(len(board)):
for j in range(len(board[0])):
if board[i][j] == '.':
for num in range(1, 10):
if self.is_valid(i, j, board, str(num)):
board[i][j] = str(num)
state = self.backtracking(board)
if state:
return True
board[i][j] = '.'
return False
return True
def is_valid(self, row, col, board, num):
for j in range(len(board[0])):
if board[row][j] == num:
return False
for i in range(len(board)):
if board[i][col] == num:
return False
start_row = (row//3)*3
start_col = (col//3)*3
for i in range(start_row, start_row+3):
for j in range(start_col, start_col+3):
if board[i][j] == num:
return False
return True
def solveSudoku(self, board):
"""
:type board: List[List[str]]
:rtype: None Do not return anything, modify board in-place instead.
"""
self.backtracking(board)
和N皇后问题不一样的是,此题涉及到二维递归,因此实际上是三层for循环嵌套