DFS手写排列

2023-07-11,,

DFS手写排列

虽然python中有自带的排列函数,但是在某些特殊情况需要手写排列。掌握了DFS手写排列对DFS的理解有一定的帮助。

1.手写排列(非字典序输出)

这种代码比较简单易懂,但是不是按照字典序输出。

思路

拿sta作为起始数和后面每一个数交换,sta+1再与后面的每一个数交换。

例如:1 2 3 4 ,1作为sta和后面的2进行交换变成 2 1 3 4 。

然后sta移动一位,再与后面的数交换。因为第一个数改变了,所以后面的数每次改变的数都和 1 2 3 4 是不同的,也就是新的一种排列。

具体操作写一个dfs()函数每次交换完后,把传进函数里的参数+1(sta移动一位)

def dfs(sta, end):
if sta == end:
print(li[0 : end + 1])
else:
for i in range(sta, end + 1):
li[sta], li[i] = li[i], li[sta]
dfs(sta + 1, end)
li[i], li[sta] = li[sta], li[i]

我们知道每次递归都需要写一个条件来结束递归,代码中的结束条件 sta == end 就代表sta后面已经没有可交换的数了,所以输出结果。

for i in range(sta, end + 1):
li[sta], li[i] = li[i], li[sta]
dfs(sta + 1, end)
li[i], li[sta] = li[sta], li[i]

代码里的这个 for 循环中的 i 就代表sta后面需要交换的数。

交换后完成了输出还要再交换回来。

例如:1 2 3 递归第一层 for 循环 i 可以取到 0、1、2。第一层 i 是0的时候递归到第二层还是 1 2 3 (我的例子只有三个数,递归的第三层就是输出结果)第二层 for 循环的 i 可以取到 1 和 2。i 是 1的时候2是和自己交换,然后输出 1 2 3。i 是 2的时候2是和3换,输出 1 3 2。如果不换回来的话,递归第一层 i 是 1 的时候本来到第二层是 2 1 3,但由于之前没有交换回来,第一层 for 循环 i 是 0 情况的最后一个数 1 3 2 被保留了下来,所以第一层 for 循环 i 是 1 时候的第二层的数就会变成 3 1 2,以至于后面一直出错。我们需要的是每次在 1 2 3 原数中进行交换,所以输出完后要交换回来。

整体代码

代码是 1 2 3 的全排列输出:

def dfs(sta, end):
if sta == end:
print(li[0 : end + 1])
else:
for i in range(sta, end + 1):
li[sta], li[i] = li[i], li[sta]
dfs(sta + 1, end)
li[i], li[sta] = li[sta], li[i] li = [i for i in range(1, 10)]
dfs(0, 2)

2.手写排列(字典序输出)

这种代码在手写排列中用的很多,输出也是按照字典序输出的。

思路

每次选一个数锁定,锁定的数不能再选,通过循环按顺序找到没被锁定的数添加,最后输出。我们需要定义以下几个列表:

a = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 用来排列
b = [0] * 10 # 用于输出
vis = [False] * 10 # 表示锁定
n = 3 # 需要排列的个数

下面是dfs()函数的定义:

def dfs(s, t):
if s == t:
print(b[0: n])
else:
for i in range(t):
if not vis[i]:
vis[i] = True
b[s] = a[i]
dfs(s+1, t)
vis[i] = False

递归的结束条件是递归深度达到了需要排列的个数。

for 循环每次取一个数,if 语句来判断这个数是否被锁定,如果没有被锁定在 b 列表中添加这个数,递归深度+1,然后继续判断数有没有被锁定。

这个思路有点像用暴力法手写排列组合,不过暴力法是用很多个 for 循环,每一个 for 循环写循环的范围来避免重复,而DFS这种写法是用了一个 vis 列表代表锁定来避免重复。

和上面的情况一样,输出完之后,上了锁的要解锁!

因为每次 for 循环是顺序查找有无上锁,所以输出也是按照字典序输出的。

整体代码

代码是 1 2 3 的全排列按照字典序输出:

def dfs(s, t):
if s == t:
print(b[0: n])
else:
for i in range(t):
if not vis[i]:
vis[i] = True
b[s] = a[i]
dfs(s+1, t)
vis[i] = False a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [0] * 10
vis = [False] * 10
n = 3
dfs(0, n)

var code = “d29a9066-194e-4cb5-bc78-72ecaba56faf”

DFS手写排列的相关教程结束。

《DFS手写排列.doc》

下载本文的Word格式文档,以方便收藏与打印。