目录
332.重新安排行程
题目链接:
思路
说实话,第一次见到这个题挺懵逼的,我感觉这好像就是图的深度优先搜索,一写起来根本不会写,甚至还有带回路的图。。。 (每日崩溃1/1)最后是照着答案敲了一遍,所以思路还是看链接吧。
代码
from collections import defaultdict
class Solution:
def findItinerary(self, tickets):
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) # 将当前机场添加到行程路径中
51.N皇后
思路
这道题很经典了吧[Doge],入门必备的那种,这道题比下一道容易的原因是每次放皇后时根本不需要担心两个皇后会不会出现在同一行,(因为每次递归行数都会+1),相当于只要考虑是不是同一列上和主副对角线上有没有就可以了。
代码
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
result = [] # 存储最终结果的二维字符串数组
chessboard = ['.' * n for _ in range(n)] # 初始化棋盘
self.backtracking(n, 0, chessboard, result) # 回溯求解
return [[''.join(row) for row in solution] for solution in result] # 返回结果集
def backtracking(self, n: int, row: int, chessboard: List[str], result: List[List[str]]) -> None:
if row == n:
result.append(chessboard[:]) # 棋盘填满,将当前解加入结果集
return
for col in range(n):
if self.isValid(row, col, chessboard):
chessboard[row] = chessboard[row][:col] + 'Q' + chessboard[row][col+1:] # 放置皇后
self.backtracking(n, row + 1, chessboard, result) # 递归到下一行
chessboard[row] = chessboard[row][:col] + '.' + chessboard[row][col+1:] # 回溯,撤销当前位置的皇后
def isValid(self, row: int, col: int, chessboard: List[str]) -> bool:
# 检查列
for i in range(row):
if chessboard[i][col] == 'Q':
return False # 当前列已经存在皇后,不合法
# 检查 45 度角是否有皇后
i, j = row - 1, col - 1
while i >= 0 and j >= 0:
if chessboard[i][j] == 'Q':
return False # 左上方向已经存在皇后,不合法
i -= 1
j -= 1
# 检查 135 度角是否有皇后
i, j = row - 1, col + 1
while i >= 0 and j < len(chessboard):
if chessboard[i][j] == 'Q':
return False # 右上方向已经存在皇后,不合法
i -= 1
j += 1
return True # 当前位置合法
37.解数独
思路
第一眼看,我嘞个豆。。。这道题有点像纸老虎,冷静思考之后其实也还行。就是二维遍历整个棋盘,对每一个空位进行尝试,然后递归到下个空位进行尝试,如果成功一直递归到最后,如果失败就返回。check()函数的三种情况仔细想想不难考虑。
代码
class Solution:
def solveSudoku(self, board: List[List[str]]) -> None:
self.backtracking(board)
"""
Do not return anything, modify board in-place instead.
"""
def backtracking(self, board):
# 若有解,返回True;若无解,返回False
for row in range(9):
for col in range(9):
# 若空格内已有数字,跳过
if board[row][col] != ".":
continue
for val in range(1, 10):
val = str(val)
if self.check(row, col, val, board):
board[row][col] = val # 细节str()输出里面全都是str,不能用int,此处我上面统一加过了。
# 下面这里最关键,要写成if self。backtracking(): return True
if self.backtracking(board):
return True
# 如果上面没有return True一层层回溯的的话,下面这一行就会生效,就回溯了,结束就无法输出了。
board[row][col] = "."
# 若数字1-9都不能成功填入空格,返回False无解
return False
return True
def check(self, row, col, val, board):
# 判断同一行是否冲突
for i in range(9):
if board[row][i] == val:
return False
# 判断同一列是否冲突
for i in range(9):
if board[i][col] == val:
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] == val:
return False
return True
总结
回溯到这里就正式结束了,后面开始学贪心算法。go go go