585 字
3 分钟
代码随想录算法训练营第二十二天 | 回溯算法 Part04

全排列问题(Permutation)#

全排列是回溯算法中的高级应用,目标是在一个集合中找出所有可能的排列方式。
它强调顺序性,并且需要追踪每个元素是否已经使用。


🔸 考点梳理#

  • ✅ 元素是否已使用(通常需要布尔数组或 set 标记)
  • ✅ 去重:对输入排序 + 跳过重复分支
  • ✅ 特殊问题(如 N 皇后):在排列基础上加入位置合法性判断

491. 递增子序列#

LeetCode 491. 递增子序列

class Solution:
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
self.path = []
self.res = []
self.backtrack(nums, 0)
return self.res
def backtrack(self, nums, start):
if len(self.path) >= 2:
self.res.append(self.path[:])
# 记录本层使用过的数字,防止同一层重复使用相同元素
used = set()
for i in range(start, len(nums)):
if self.path and self.path[-1] > nums[i]:
continue # 递增限制
if nums[i] in used:
continue # 同层去重
used.add(nums[i])
self.path.append(nums[i])
self.backtrack(nums, i + 1)
self.path.pop()

46. 全排列#

LeetCode 46. 全排列

class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
self.path = []
self.res = []
self.used = []
self.backtrack(nums)
return self.res
def backtrack(self, nums):
if len(self.path) == len(nums):
self.res.append(self.path[:])
return
for i in range(len(nums)):
if nums[i] in self.used:
continue
self.path.append(nums[i])
self.used.append(nums[i])
self.backtrack(nums)
self.path.pop()
self.used.pop()

47. 全排列 II(含重复元素)#

LeetCode 47. 全排列 II

class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
self.path = []
self.res = []
self.used = [False] * len(nums)
nums.sort() # 排序是剪枝的前提
self.backtrack(nums)
return self.res
def backtrack(self, nums):
if len(self.path) == len(nums):
self.res.append(self.path[:])
return
for i in range(len(nums)):
if self.used[i]:
continue
# 剪枝:前一个值和当前值相等,且前一个值还未使用,则跳过
if i > 0 and nums[i] == nums[i - 1] and not self.used[i - 1]:
continue
self.path.append(nums[i])
self.used[i] = True
self.backtrack(nums)
self.path.pop()
self.used[i] = False

51. N 皇后#

LeetCode 51. N 皇后

class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
self.res = []
board = ["." * n for _ in range(n)] # 初始化棋盘
self.backtrack(board, 0)
return self.res
def backtrack(self, board: List[str], row: int) -> None:
if row == len(board):
self.res.append(board[:]) # 注意需复制当前棋盘
return
n = len(board)
for col in range(n):
if not self.isValid(board, row, col):
continue
# 放置皇后
board[row] = board[row][:col] + 'Q' + board[row][col + 1:]
self.backtrack(board, row + 1)
# 撤销选择
board[row] = board[row][:col] + '.' + board[row][col + 1:]
def isValid(self, board: List[str], row: int, col: int) -> bool:
n = len(board)
# 检查列是否有皇后
for i in range(row):
if board[i][col] == 'Q':
return False
# 检查右上对角线
for i, j in zip(range(row - 1, -1, -1), range(col + 1, n)):
if board[i][j] == 'Q':
return False
# 检查左上对角线
for i, j in zip(range(row - 1, -1, -1), range(col - 1, -1, -1)):
if board[i][j] == 'Q':
return False
return True
代码随想录算法训练营第二十二天 | 回溯算法 Part04
https://fuwari.vercel.app/posts/code_musings_day_twenty-two/
作者
Jarrett
发布于
2025-07-05
许可协议
CC BY-NC-SA 4.0