585 字
3 分钟
代码随想录算法训练营第二十二天 | 回溯算法 Part04
全排列问题(Permutation)
全排列是回溯算法中的高级应用,目标是在一个集合中找出所有可能的排列方式。
它强调顺序性,并且需要追踪每个元素是否已经使用。
🔸 考点梳理
- ✅ 元素是否已使用(通常需要布尔数组或 set 标记)
- ✅ 去重:对输入排序 + 跳过重复分支
- ✅ 特殊问题(如 N 皇后):在排列基础上加入位置合法性判断
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. 全排列
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(含重复元素)
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 皇后
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/