一、重新安排行程
1.1 题目
给你一份航线列表 tickets
,其中 tickets[i] = [fromi, toi]
表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。
所有这些机票都属于一个从 JFK
(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK
开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。
- 例如,行程
["JFK", "LGA"]
与["JFK", "LGB"]
相比就更小,排序更靠前。
假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。
示例 1:
输入:tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]] 输出:["JFK","MUC","LHR","SFO","SJC"]
示例 2:
输入:tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]] 输出:["JFK","ATL","JFK","SFO","ATL","SFO"] 解释:另一种有效的行程是 ["JFK","SFO","ATL","JFK","ATL","SFO"] ,但是它字典排序更大更靠后。
提示:
1 <= tickets.length <= 300
tickets[i].length == 2
fromi.length == 3
toi.length == 3
fromi
和toi
由大写英文字母组成fromi != toi
1.2 题目链接
1.3 解题思路和过程想法
(1)解题思路
先对机票 Tickets 排序,以保证优先选择字典序最小的票。因需保证出发点是 “JFK",在递归之前传入起始节点。再用 for 遍历“第一个”地点,递归纵向处理后续的节点。递归函数需带返回值,找到当前要找的内容就结束,再重新找其他出发地(因为可能有多种符合要求的情况,但我们只返回最好的那种,故而需要提前返回)。
# 判断细节:出发起点符合要求,且该票尚未使用
# 回溯函数的参数:必要参数 tickets,path,res,
辅助变量:标记是否使用的 used 数组,当前要找的出发地
# 递归出口:路径长度比机票数多1
(2)过程想法
有大体的处理思路,但没想到怎么写处理细节
1.4 代码(代码提醒超时)
class Solution:
def backTracing(self,tickets,cur,used,path,res):
# 递归出口:路径长度比机票张数多1
if len(path) == len(tickets)+1:
res.append(path[:])
return True
for i,ticket in enumerate(tickets):
# 当前票的起始站为要找的,并且该票还没使用
if ticket[0] == cur and used[i] == 0:
path.append(ticket[1])
used[i] = 1
state = self.backTracing(tickets,ticket[1],used,path,res)
path.pop()
used[i] = 0
# 找到一个合适的结果就结束
if state:
return True
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
# 为优先字典排序更小的,先对其排序
tickets.sort()
# 标记是否使用过
used = [0] * len(tickets)
# 初始化出发点
path = ["JFK"]
res = []
self.backTracing(tickets,"JFK",used,path,res)
return res[0]
二、N 皇后
2.1 题目
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n
个皇后放置在 n×n
的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n
,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q'
和 '.'
分别代表了皇后和空位。
示例 1:
输入:n = 4 输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] 解释:如上图所示,4 皇后问题存在两个不同的解法。
示例 2:
输入:n = 1 输出:[["Q"]]
提示:
1 <= n <= 9
2.2 题目链接
2.3 解题思路和过程想法
(1)解题思路
用 for 遍历“第一行”地点,递归纵向处理其他行的皇后。若当前皇后符合要求,则递归相下判断其他皇后的位置,否则弹出当前皇后的位置,重新尝试其他位置。直到找到所有位置。
# 判断细节:当前位置与其他皇后不冲突
# 回溯函数的参数:必要参数 n,row,col,chessboard
# 递归出口:找到所有位置
(2)过程想法
可以直接写出代码,但是对于最后结果形式的转换不熟练
2.4 代码
class Solution:
def isValid(self,row,col,chessBoard,n) -> bool:
# 列
for i in range(row):
if chessBoard[i][col] == 'Q':
return False
# 右斜线
i,j = row-1,col+1
while i >= 0 and j < n:
if chessBoard[i][j] == 'Q':
return False
i -= 1
j += 1
# 左斜线
i,j = row-1,col-1
while i >= 0 and j >= 0:
if chessBoard[i][j] == 'Q':
return False
i -= 1
j -= 1
return True
def backTracing(self,n,row,chessBoard,res):
if row == n:
res.append(chessBoard[:])
return
for col in range(n):
if self.isValid(row,col,chessBoard,n):
chessBoard[row] = chessBoard[row][:col] + 'Q' + chessBoard[row][col+1:]
self.backTracing(n,row+1,chessBoard,res)
chessBoard[row] = chessBoard[row][:col] + '.' + chessBoard[row][col+1:]
def solveNQueens(self, n: int) -> List[List[str]]:
chessBoard = ['.' * n for _ in range(n)]
res = []
self.backTracing(n,0,chessBoard,res)
return [[''.join(row) for row in solution] for solution in res]
三、解数独
3.1 题目
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
- 数字
1-9
在每一行只能出现一次。 - 数字
1-9
在每一列只能出现一次。 - 数字
1-9
在每一个以粗实线分隔的3x3
宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 '.'
表示。
示例 1:
输入:board = [["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]] 输出:[["5","3","4","6","7","8","9","1","2"],["6","7","2","1","9","5","3","4","8"],["1","9","8","3","4","2","5","6","7"],["8","5","9","7","6","1","4","2","3"],["4","2","6","8","5","3","7","9","1"],["7","1","3","9","2","4","8","5","6"],["9","6","1","5","3","7","2","8","4"],["2","8","7","4","1","9","6","3","5"],["3","4","5","2","8","6","1","7","9"]] 解释:输入的数独如上图所示,唯一有效的解决方案如下所示:
提示:
board.length == 9
board[i].length == 9
board[i][j]
是一位数字或者'.'
- 题目数据 保证 输入数独仅有一个解
3.2 题目链接
3.3 解题思路和过程想法
(1)解题思路
因为棋盘是二维的,考虑使用两个 for 语句来表示棋盘位置。用 for 遍历9个数字,递归纵向处理后续的节点。递归函数需带返回值,找到合适的数字,其他数层就不再搜索了,提前返回。
解释:
在 backTracing() 函数中,当为某个位置(i, j)找到一个有效数字时,就会将其赋值给board[i][j]。然后递归调用该函数求解下一个位置。但如果下一个位置有多个有效选项,函数会用不同的数字覆盖当前位置的数字,这就太糟糕了,会导致出错且无限循环。
在引入返回值后,当为位置 (i, j) 找到一个有效数字时,函数会通过递归调用自身来检查该数字是否导致一个有效的解。如果当前数字指向一个有效解,函数返回 True,表示找到了一个解。如果没有,函数会回溯,将当前位置设置为".",然后继续搜索其他有效数字。
# 判断细节:当前位置与其他数字不冲突
# 回溯函数的参数:必要参数 board
辅助变量:标记是否使用的 used 数组,当前要找的出发地
# 递归出口(隐性):处理完所有节点
(2)过程想法
有具体的处理思路,但没想到递归函数需要用返回值
3.4 代码
class Solution:
def haveNum(self,board,row,col) -> bool:
if board[row][col] != '.':
return True
else:
return False
def isValid(self,board,row,col,c) -> bool:
# 行
for j in range(9):
if board[row][j] == c:
return False
# 列
for i in range(9):
if board[i][col] == c:
return False
# 当前小方格
startX = (row // 3) * 3
startY = (col // 3) * 3
for i in range(startX,startX+3):
for j in range(startY,startY+3):
if board[i][j] == c:
return False
return True
def backTracing(self,board) -> bool:
# for k 语句遍历第一个元素,递归纵向处理其他元素
for i in range(9):
for j in range(9):
if self.haveNum(board,i,j):
continue
for k in range(1,10):
if self.isValid(board,i,j,str(k)):
board[i][j] = str(k)
if self.backTracing(board): return True
board[i][j] = '.'
# 9个数都试完了还没成功
return False
return True
def solveSudoku(self, board: List[List[str]]) -> None:
self.backTracing(board)