问题描述:一个位置上有m种可能,一共n个位置,求所有可能的排列
解法1:分解法
灵感来源于线性代数中的矩阵乘法。
数字结果计算过程不就是n个m相乘吗,我们可以把这个过程拆分为2个为一组的多个二元运算。
假设n=3,m=2
那 2^3=2*2*2=(2*2)*2=4*2
转换成数组也是一样的
所以我们可以定义一种特殊的乘法:两个数组中的元素两两组合
假设:m=[1,2]
m*m*m=(m*m)*m
m*m=[1,2]*[1,2]=[[1, 1], [1, 2], [2, 1], [2, 2]]
(m*m)*m=[[1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 2, 2], [2, 1, 1], [2, 1, 2], [2, 2, 1], [2, 2, 2]]
我们只需要使用这种特殊的乘法,每次都乘上一个m,n-1次运算后便可得到结果。
解法2:深度优先搜索/回溯法(非递归)(迭代法)
相当于一颗多叉树,每个非叶节点有m个子节点,深搜的一条路径便是一种排列。
我们可以加上层数信息来区分这些节点。
算法描述如下:
1.初始化:将m个元素入栈,层数为0,创建一个临时数组:temp 长度为n
2.如果栈非空,弹出栈顶元素,修改temp[层数]=栈顶元素,如果层数等于n-1则将temp加入到结果中否则将m个元素入栈,层数为depth+1
3.重复执行步骤2,直到栈为空
解法1代码:
def multiply(a,b):
r=[]
for i in a:
for j in b:
if isinstance(i,list):
temp=i[:]
temp.append(j)
r.append(temp)
else:
r.append([i,j])
return r
if __name__ == "__main__":
a=[1,2]
m=len(a)
n=3
b=a
while n>1:
a=multiply(a,b)
n-=1
print(a)
print(len(a))
解法2代码:
if __name__ == "__main__":
a = [1, 2, 3]
m = len(a)
n = 3
depth=0
stack=[]
for i in range(m):
stack.append([depth,a[i]])
r=[]
temp=[-1]*n
while stack:
v=stack.pop()
depth=v[0]
temp[depth]=v[1]
if depth==n-1:
r.append(temp[:])
else:
for i in range(m):
stack.append([depth+1, a[i]])
print(r)
print(len(r))
结果示例: