系列文章目录
代码随想录算法训练营第一天|数组理论基础,704. 二分查找,27. 移除元素
代码随想录算法训练营第二天|977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II
代码随想录算法训练营第三天|链表理论基础,203.移除链表元素,707.设计链表,206.反转链表
代码随想录算法训练营第四天|24. 两两交换链表中的节点,19.删除链表的倒数第N个节点,面试题 02.07. 链表相交,142.环形链表II,总结
代码随想录算法训练营第五天|哈希表理论基础,242.有效的字母异位词,349. 两个数组的交集,202. 快乐数,1. 两数之和
代码随想录算法训练营第六天|454.四数相加II,383. 赎金信,15. 三数之和,18. 四数之和,总结
代码随想录算法训练营第七天|344.反转字符串,541. 反转字符串II,卡码网:54.替换数字,151.翻转字符串里的单词,卡码网:55.右旋转字符串
代码随想录算法训练营第八天|28. 实现 strStr(),459.重复的子字符串,字符串总结,双指针回顾
代码随想录算法训练营第九天|理论基础,232.用栈实现队列,225. 用队列实现栈
代码随想录算法训练营第十天|20. 有效的括号,1047. 删除字符串中的所有相邻重复项,150. 逆波兰表达式求值
代码随想录算法训练营第十一天|239. 滑动窗口最大值,347.前 K 个高频元素,总结
代码随想录算法训练营第十二天|理论基础,递归遍历,迭代遍历,统一迭代
代码随想录算法训练营第十三天|层序遍历10,226.翻转二叉树,101.对称二叉树
代码随想录算法训练营第十四天|104.二叉树的最大深度,559.n叉树的最大深度,111.二叉树的最小深度,222.完全二叉树的节点个数
代码随想录算法训练营第十五天|110.平衡二叉树,257. 二叉树的所有路径,404.左叶子之和
代码随想录算法训练营第十六天|513.找树左下角的值,112. 路径总和,113.路径总和ii,106.从中序与后序遍历序列构造二叉树,105.从前序与中序遍历序列构造二叉树
代码随想录算法训练营第十七天|654.最大二叉树,617.合并二叉树,700.二叉搜索树中的搜索,98.验证二叉搜索树
代码随想录算法训练营第十八天|530.二叉搜索树的最小绝对差,501.二叉搜索树中的众数,236. 二叉树的最近公共祖先
代码随想录算法训练营第十九天|235. 二叉搜索树的最近公共祖先,701.二叉搜索树中的插入操作,450.删除二叉搜索树中的节点
代码随想录算法训练营第二十天|669. 修剪二叉搜索树,108.将有序数组转换为二叉搜索树,538.把二叉搜索树转换为累加树,总结篇
代码随想录算法训练营第二十一天|回溯算法理论基础,77. 组合
代码随想录算法训练营第二十二天|216.组合总和III,17.电话号码的字母组合
代码随想录算法训练营第二十三天|39. 组合总和,40.组合总和II,131.分割回文串
代码随想录算法训练营第二十四天|93.复原IP地址,78.子集,90.子集II
代码随想录算法训练营第二十五天|491.递增子序列,46.全排列,47.全排列 II
文章目录
- 系列文章目录
- 332.重新安排行程
- 51. N皇后
- 37. 解数独
- 总结
332.重新安排行程
题目链接: 332.重新安排行程
题目内容: 给你一份航线列表 tickets ,其中 tickets[i] = [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。例如,行程 [“JFK”, “LGA”] 与 [“JFK”, “LGB”] 相比就更小,排序更靠前。假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。
思路:
- 一个行程中,如果航班处理不好容易变成一个圈,成为死循环
- 有多种解法,字母序靠前排在前面,需要正确记录映射关系
- 回溯法的树形结构绘制
- 递归函数参数:result数组,path数组,targetnum:(表示有多少个航班,用于终止条件)
- 递归终止条件:遇到的机场个数达到了航班数量+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皇后
题目链接: 51.N皇后
题目内容: 按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
视频讲解: 这就是传说中的N皇后? 回溯算法安排!| LeetCode:51.N皇后
result是三维数组
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,row,chessboard,result):
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,col,chessboard):
#检查列
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. 解数独
题目链接: 37.解数独
题目内容: 编写一个程序,通过填充空格来解决数独问题。数独的解法需 遵循如下规则:数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
视频讲解: 回溯算法二维递归?解数独不过如此!| LeetCode:37. 解数独
核心思路:二维递归+回溯
棋盘的每一个位置都要放一个数字(而N皇后是一行只放一个皇后),并检查数字是否合法,解数独的树形结构要比N皇后更宽更深。
class Solution:
def solveSudoku(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
self.backtracking(board)
def backtracking(self,board):
for i in range(len(board)):
for j in range(len(board[0])):
if board[i][j] != '.':
continue
for k in range(1,10):
if self.is_valid(i,j,k,board):
board[i][j] = str(k)
if self.backtracking(board):
return True
board[i][j] = '.'
return False
return True
def is_valid(self,row,col,val,board):
#检查同一行是否有冲突
for i in range(9):
if board[row][i]==str(val):
return False
#检查同一列是否有冲突
for i in range(9):
if board[i][col]==str(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] == str(val):
return False
return True
总结
组合问题:N个数里面按一定规则找出k个数的集合
排列问题:N个数按一定规则全排列,有几种排列方式
切割问题:一个字符串按一定规则有几种切割方式
子集问题:一个N个数的集合里有多少符合条件的子集
棋盘问题:N皇后,解数独等等