9.子集II
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
class Solution:
def __init__(self):
self.path = []
self.paths = []
def subsetWithDup(self,nums):
self.path.clear()
self.paths.clear()
nums.sort()
self.backtracking(nums, 0)
return self.paths
def backtracking(self, nums, startIndex):
self.paths.append(self.path[:])
if startIndex == len(nums):
return
for i in range(startIndex, len(nums)):
if i > startIndex and nums[i] == nums[i - 1]:
continue
self.path.append(nums[i])
self.backtracking(nums, i + 1)
self.path.pop()
10.递增子序列
给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。
class Solution:
def __init__(self):
self.path = []
self.paths = []
def findSubsequences(self, nums):
self.path.clear()
self.paths.clear()
self.backstracking(nums, 0)
return self.paths
def backstracking(self, nums, startIndex):
if len(self.path) >= 2:
self.paths.append(self.path[:])
if startIndex == len(nums):
return
# 单层递归逻辑
# 深度遍历中每一层都会有一个全新的usage_list用于记录本层元素是否重复使用
usage_list = set()
for i in range(startIndex, len(nums)):
# 若当前元素值小于前一个时(非递增)或者曾用过,跳入下一循环
if (self.path and self.path[-1] > nums[i]) or nums[i] in usage_list:
continue
usage_list.add(nums[i])
self.path.append(nums[i])
self.backstracking(nums, i + 1)
self.path.pop()
11.全排列
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
class Solution:
def __init__(self):
self.path = []
self.paths = []
def permute(self, nums):
'''
因为本题排列是有序的,这意味着同一层的元素可以重复使用,但同一树枝上不能重复使用
所以处理排列问题每层都需要从头搜索,故不再使用start_index
'''
self.backstracking(nums)
return self.paths
def backstracking(self, nums):
if len(self.path) == len(nums):
self.paths.append(self.path[:])
return
for i in range(len(nums)):
if nums[i] in self.path:
continue
self.path.append(nums[i])
self.backstracking(nums)
self.path.pop()
12.全排列 II
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
class Solution:
def __init__(self):
self.path = []
self.paths = []
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
nums.sort()
used = [0] * len(nums)
self.backstracking(nums, used)
return self.paths
def backstracking(self, nums, used):
if len(self.path) == len(nums):
self.paths.append(self.path[:])
return
for i in range(len(nums)):
if not used[i]:
if i > 0 and nums[i] == nums[i - 1] and used[i - 1] == 1:
continue
used[i] = 1
self.path.append(nums[i])
self.backstracking(nums, used)
self.path.pop()
used[i] = 0
13.重新安排行程
给定一个机票的字符串二维数组 [from, to],子数组中的两个成员分别表示飞机出发和降落的机场地点,对该行程进行重新规划排序。所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。
提示:
- 如果存在多种有效的行程,请你按字符自然排序返回最小的行程组合。例如,行程 ["JFK", "LGA"] 与 ["JFK", "LGB"] 相比就更小,排序更靠前
- 所有的机场都用三个大写字母表示(机场代码)。
- 假定所有机票至少存在一种合理的行程。
- 所有的机票必须都用一次 且 只能用一次。
class Solution():
def findItinerary(self, tickets):
tickets_dict = collections.defaultdict(list)
for item in tickets:
tickets_dict[item[0]].append(item[1])
'''
tickets_dict里面的内容是这样的
{'JFK': ['SFO', 'ATL'], 'SFO': ['ATL'], 'ATL': ['JFK', 'SFO']})
'''
path = ['JFK']
def backtracking(start_point):
if len(path) == len(tickets) + 1:
return True
tickets_dict[start_point].sort()
for _ in tickets_dict[start_point]:
end_point = tickets_dict[start_point].pop(0)
path.append(end_point)
if backtracking(end_point):
return True
path.pop()
tickets_dict[start_point].append(end_point)
backtracking('JFK')
return path
14.N皇后
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
class Solution:
def solveNQueens(self, n: int):
if not n:return []
board = [['.'] * n for _ in range(n)]
res = []
def is_Vaild(board, row, col):
# 判断同一列是否冲突
for i in range(len(board)):
if board[i][col] == 'Q':
return False
# 判断左上角是否冲突
i = row - 1
j = col - 1
while i >= 0 and j >= 0:
if board[i][j] == 'Q':
return False
i -= 1
j -= 1
# 判断右上角是否冲突
i = row - 1
j = col + 1
while i >= 0 and j < len(board):
if board[i][j] == 'Q':
return False
i -= 1
j += 1
return True
def backtracking(board, row, n):
#如果走到最后一行,说明已经找到一个解
if row == n:
temp_res = []
for temp in board:
temp_str = ''.join(temp)
temp_res.append(temp_str)
res.append(temp_res)
for col in range(n):
if not is_Vaild(board, row, col):
continue
board[row][col] = 'Q'
backtracking(board, row + 1, n)
board[row][col] = '.'
backtracking(board, 0, n)
return res
15.解数独
编写一个程序,通过填充空格来解决数独问题。
一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 空白格用 '.' 表示。
class Solution:
def solveSudoku(self, board) -> None:
self.backtracking(board)
def backtracking(self, board):
# 若有解,返回True;若无解,返回False
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_vaild(i, j, k, board):
board[i][j] = str(k)
if self.backtracking(board):return True
board[i][j] = '.'
# 若数字1-9都不能成功填入空格,返回False无解
return False
return True
def is_vaild(self, row, col, val, board):
# 判断同一行是否冲突
for i in range(9):
if board[row][i] == str(val):
return False
# 判断同一列是否冲突
for j in range(9):
if board[j][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