46. 全排列
给定一个不含重复数字的数组 nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
注意:排列问题的话是要求树枝不重复,树层可以重复,因此选择用used数组来记录,当used[i]等于true的时候说明在该树枝中used[i]已经用过了。
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
answer = []
used = [False] * len(nums)
self.backtracking(nums, used, [], answer)
return answer
def backtracking(self, nums, used, cur, answer):
if len(cur) == len(nums):
answer.append(cur[:])
return
# 注意:排列问题的for是要遍历全部nums
for i in range(len(nums)):
if used[i]:
continue
cur.append(nums[i])
used[i] = True
self.backtracking(nums, used, cur, answer)
cur.pop()
used[i] = False
47. 全排列 II
给定一个可包含重复数字的序列 nums
,按任意顺序 返回所有不重复的全排列。
注意:这里要求不重复,那么树层也不能重复
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
answer = []
used = [False] * len(nums)
#注意这里要有序,否则重复的数字不能相邻
nums.sort()
self.backtracking(nums, used, [], answer)
return answer
def backtracking(self, nums, used, cur, answer):
if len(cur) == len(nums):
answer.append(cur[:])
return
for i in range(len(nums)):
if used[i]:
continue
if i > 0 and nums[i] == nums[i-1] and not used[i-1]: # 注意这里是not used[i-1]
continue
cur.append(nums[i])
used[i] = True
self.backtracking(nums, used, cur, answer)
used[i] = False
cur.pop()
332. 重新安排行程
给你一份航线列表 tickets
,其中 tickets[i] = [fromi, toi]
表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。
所有这些机票都属于一个从 JFK
(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK
开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。
- 例如,行程
["JFK", "LGA"]
与["JFK", "LGB"]
相比就更小,排序更靠前。
假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。
错误:运行超时
class Solution:
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
answer = []
used = [False] * len(tickets)
self.backtracking(tickets, used, ["JFK"], answer)
answer.sort()
return answer[0]
def backtracking(self, tickets, used, cur, answer):
if len(cur) == len(tickets) + 1:
answer.append(cur[:])
return
for i in range(len(tickets)):
if used[i]:
continue
if tickets[i][0] == cur[-1]:
cur.append(tickets[i][1])
used[i] = True
self.backtracking(tickets, used, cur, answer)
cur.pop()
used[i] = False
正解:
这一题的关键在于理解思路
class Solution:
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
# self.map_dict = {}
map_dict = defaultdict(list) # 创建默认字典,用于存储机场映射关系
for ticket in tickets:
# if ticket[0] not in map_dict.keys():
# self.map_dict[ticket[0]] = []
# self.map_dict[ticket[0]].append(ticket[1])
map_dict[ticket[0]].append(ticket[1])
# 对到达机场列表进行字母逆序排序, 确保最后得到的answer是字典排序最小。
for key in map_dict:
map_dict[key].sort(reverse=True)
answer = []
self.backtracking("JFK", map_dict, answer)
return answer[::-1]
def backtracking(self, depart, map_dict, answer):
while map_dict[depart]:
# 这样不对, 因为depart变了之后后面answer.append(depart)就变了。
# depart = map_dict[depart].pop()
# self.backtracking(depart, map_dict, answer)
next_depart = map_dict[depart].pop()
self.backtracking(next_depart, map_dict, answer)
answer.append(depart)
51. N皇后
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n
个皇后放置在 n×n
的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n
,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q'
和 '.'
分别代表了皇后和空位。
解法解析:
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
answer = []
# 注意:以前没用过这种表达 n=4: ['....', '....', '....', '....']
cur = ['.' * n for _ in range(n)]
self.backtracking(0, cur, answer)
# return [''.join(cur) for cur in answer]
return answer
def backtracking(self, row, cur, answer):
if row == len(cur):
answer.append(cur[:])
return
for col in range(len(cur)):
if self.is_value(row, col, cur):
cur[row] = cur[row][:col] + 'Q' + cur[row][col+1:]
self.backtracking(row+1, cur, answer)
cur[row] = cur[row][:col] + '.' + cur[row][col+1:]
def is_value(self, row, col, cur):
i = row - 1
while i >= 0:
if cur[i][col] == 'Q':
return False
i -= 1
j = col - 1
while j >= 0:
if cur[row][j] == 'Q':
return False
j -= 1
i, j = row - 1, col - 1
while i >= 0 and j >= 0:
if cur[i][j] == 'Q':
return False
i -= 1
j -= 1
i, j = row - 1, col + 1
while i >= 0 and j < len(cur):
if cur[i][j] == 'Q':
return False
i -= 1
j += 1
return True
37. 解数独
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
- 数字
1-9
在每一行只能出现一次。 - 数字
1-9
在每一列只能出现一次。 - 数字
1-9
在每一个以粗实线分隔的3x3
宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 '.'
表示。
解法解析:
纵向迭代填好一个空,比如填 '1',继续往下填下一个空,如果下一个空1-9都不符合,则复原该位置的值从 '1' 改为 '.',返回横向迭代填下一个数字 ‘2’。
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[i])):
if board[i][j] != '.':
continue
else:
for val in range(1, 10):
val = str(val)
if self.is_valide(i, j, val, board):
board[i][j] = val
if self.backtracking(board): return True
board[i][j] = '.'
return False
return True
def is_valide(self, row, col, val, board):
for j in range(len(board[row])):
if board[row][j] == val:
return False
for i in range(len(board)):
if board[i][col] == val:
return False
row = (row // 3) * 3
col = (col // 3) * 3
for i in range(3):
for j in range(3):
if board[row + i][col + j] == val:
return False
return True