python回溯算法全排列_【python刷题】回溯算法(深度优先搜索DFS)

回溯算法框架:

result = []

def backtrack(路径, 选择列表):

if 满足结束条件:

result.add(路径)

return

for 选择 in 选择列表:

做选择

backtrack(路径, 选择列表)

撤销选择

多叉树的遍历框架

def traverse(TreeNode root):

for child in root.children:

#前向遍历需要的操作

traverse(dhild)

#后向遍历需要的操作

全排列问题

def permutation(nums):

def backtrack(nums, tmp):

# 如果tmp中满了,则排列完成,将临时数组加入到res中

if len(tmp) == len(nums):

res.append(tmp[:])

return

for i in range(len(nums)):

# 选择一个数加入到tmp中,如果tmp中已存在,则继续

if nums[i] in tmp:

continue

tmp.append(nums[i])

# 递归选择

backtrack(nums, tmp)

# 将最后一个数删除

tmp.pop()

res = []

backtrack(nums, [])

return res

res = permutation([1, 2, 3])

print(res)

结果:

[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

子集问题

def subset(nums):

def trackback(nums, k, tmp):

res.append(tmp[:])

for i in range(k, len(nums)):

tmp.append(nums[i])

trackback(nums, i+1, tmp)

tmp.pop()

res = []

trackback(nums, 0, [])

return res

res = subset([1, 2, 3])

print(res)

结果:

[[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]

八皇后

from pprint import pprint

class NQueue:

def __init__(self, n):

self.board = [['.' for _ in range(n)] for _ in range(n)]

self.count = 0

self.trackback(self.board, 0)

def trackback(self, board, row):

# 从第0行开始放置

if row == len(board):

print(board)

self.count += 1

return

n = len(board)

for col in range(n):

if not self.isValid(board, row, col):

continue

board[row][col] = 'Q'

self.trackback(board, row + 1)

board[row][col] = '.'

# 是否可以在board[row][col]放置皇后

def isValid(self, board ,row, col):

n = len(board)

# 如果第rol列上存在Q,返回False

for i in range(n):

if board[i][col] == 'Q':

return False

# 检查右上方是否冲突

i,j = row-1, col+1

while i >=0 and j < n:

if board[i][j] == 'Q':

return False

i -= 1

j += 1

# 检查左上方是否冲突

i,j = row-1, col-1

while i >= 0 and j >= 0:

if board[i][j] == 'Q':

return False

i -= 1

j -= 1

return True

nQueen = NQueue(8)

pprint(nQueen.count)

结果:

92

组合

输入两个数字 n, k,算法输出 [1..n] 中 k 个数字的所有组合

比如输入 n = 4, k = 2,输出如下结果,顺序无所谓,但是不能包含重复(按照组合的定义,[1,2] 和 [2,1] 也算重复):

[

[1,2],

[1,3],

[1,4],

[2,3],

[2,4],

[3,4]

]

k 限制了树的高度,n 限制了树的宽度

def combine(n, k):

nums = [i for i in range(1, n+1)]

def trackback(nums, t, k, tmp):

if len(tmp) == k:

res.append(tmp[:])

return

for i in range(t, len(nums)):

tmp.append(nums[i])

trackback(nums, i+1, k, tmp)

tmp.pop()

res = []

trackback(nums, 0, k, [])

return res

res = combine(4, 2)

print(res)

结果:

[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]

解数独

from pprint import pprint

board = [[0 for _ in range(9)] for _ in range(9)]

def solveSudoku():

global board

# 从棋盘上的0,0位置开始

trackback(board, 0, 0)

def trackback(board, row, col):

m, n = 9, 9

# 穷举到某行的最后一列,再从下一行开始

if col == n:

return trackback(board, row+1, 0)

# 如果穷举到最后一行了, 打印棋盘,并返回True

if row == m:

pprint(board)

return True

# 每次从(row,col)位置开始,穷举到(m,n)位置

for i in range(row, m):

for j in range(col, n):

# 如果当前位置是预设了值的,就跳过,继续下一列

if board[i][j] != 0:

return trackback(board, i, j+1)

# 判断穷举出来的值是否符合规则

for k in range(1,10):

# 如果不是有效的,则继续

if not isValid(board, i, j, k):

continue

# 否则当前位置变为k

board[i][j] = k

# 如果下一列穷举返回True,返回True

if trackback(board, i, j+1):

return True

# 将i,j出还原为0,继续穷举

board[i][j] = 0

return False

return False

def isValid(board, i, j, k):

# 判断该值所在行列是否有重复

for m in range(9):

if board[i][m] == k:

return False

if board[m][j] == k:

return False

# 3×3小格中是否有重复

if board[(i//3)*3+m//3][(j//3)*3+m%3] == k:

return False

return True

solveSudoku()

结果:

[[1, 2, 3, 4, 5, 6, 7, 8, 9],

[4, 5, 6, 7, 8, 9, 1, 2, 3],

[7, 8, 9, 1, 2, 3, 4, 5, 6],

[2, 1, 4, 3, 6, 5, 8, 9, 7],

[3, 6, 5, 8, 9, 7, 2, 1, 4],

[8, 9, 7, 2, 1, 4, 3, 6, 5],

[5, 3, 1, 6, 4, 2, 9, 7, 8],

[6, 4, 2, 9, 7, 8, 5, 3, 1],

[9, 7, 8, 5, 3, 1, 6, 4, 2]]

leetcode 22. 括号生成

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

输入:n = 3

输出:["((()))","(()())","(())()","()(())","()()()"]

输入:n = 1

输出:["()"]

from pprint import pprint

def generateParenthesis(n):

res = []

trackback(n, n, [], res)

return res

# left,right用于左括号和右括号的个数

def trackback(left, right, tmp, res):

if right < left:

return

if left < 0 or right < 0:

return

if left == 0 and right == 0:

res.append(tmp[:])

return

tmp.append('(')

trackback(left-1, right, tmp, res)

tmp.pop()

tmp.append(')')

trackback(left, right-1, tmp, res)

tmp.pop()

res = generateParenthesis(3)

pprint(res)from pprint import pprint

def generateParenthesis(n):

res = []

trackback(n, n, [], res)

return res

# left,right用于左括号和右括号的个数

def trackback(left, right, tmp, res):

if right < left:

return

if left < 0 or right < 0:

return

if left == 0 and right == 0:

res.append(tmp[:])

return

tmp.append('(')

trackback(left-1, right, tmp, res)

tmp.pop()

tmp.append(')')

trackback(left, right-1, tmp, res)

tmp.pop()

res = generateParenthesis(3)

pprint(res)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回溯算法是一种穷举搜索方法,通过逐步构建解决方案并撤销选择来找到所有可能的解决方案。在使用回溯算法时,我们需要考虑三个问题:可选列表、已选列表和结束条件。可选列表是指所有可以选择的元素,已选列表是指已经做出的选择,而结束条件是指已选列表满足题目条件时可以结束穷举。 下面是一个Python实现的回溯算法框架: ``` def backtrack(选择列表, 路径): if 终止条件: 存放结果 return for 选择 in 选择列表(本层集合中元素): 处理节点 backtrack(选择列表, 路径) 回溯,撤销处理结果 ``` 对于全排列问题,我们可以使用回溯算法来生成所有可能的排列。以下是一个使用回溯算法生成全排列Python代码示例: ```python def permute(nums): def backtrack(first=0): if first == n: res.append(nums[:]) for i in range(first, n): nums[first], nums[i = nums[i], nums[first] backtrack(first + 1) nums[first], nums[i = nums[i], nums[first] n = len(nums) res = [] backtrack() return res ``` 这段代码中,我们定义了一个回溯函数`backtrack`,它用于递归地生成所有可能的排列。在每个递归步骤中,我们将当前位置的元素与后面的元素进行交换,然后递归地生成下一个位置的排列。当所有位置都填满时,我们将当前排列加入结果列表。 你可以使用这个函数来生成给定列表的全排列。例如,对于输入``,该函数将返回`[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 2, 1], [3, 1, 2]]`作为结果。 请注意,这只是回溯算法的一种实现方式,可能还有其他方法来解决全排列问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [python 回溯法生成全排列](https://blog.csdn.net/weixin_55617081/article/details/125809941)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [Python每日一练-----全排列(回溯思想)](https://blog.csdn.net/m0_61791601/article/details/123971263)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值