Python 计算列表的可能排列数,只要它是';适合';进入另一个列表
我试图找出一个列表的多少个排列是可能的,每个排列“适合”到另一个列表中(即,排列的所有元素必须小于或等于相应的元素)。例如,列表Python 计算列表的可能排列数,只要它是';适合';进入另一个列表,python,permutation,Python,Permutation,我试图找出一个列表的多少个排列是可能的,每个排列“适合”到另一个列表中(即,排列的所有元素必须小于或等于相应的元素)。例如,列表[1,2,3,4]必须适合列表[2,4,3,4] 在这种情况下,有8种可能的安排: [1, 2, 3, 4] [1, 4, 2, 3] [1, 3, 2, 4] [1, 4, 3, 2] [2, 1, 3, 4] [2, 4, 1, 3] [2, 3, 1, 4] [2, 4, 3, 1] 因为3和4不能放入列表的第一个插槽,所以所有以3或4开头的排列都将被删除。此外
[1,2,3,4]
必须适合列表[2,4,3,4]
在这种情况下,有8种可能的安排:
[1, 2, 3, 4]
[1, 4, 2, 3]
[1, 3, 2, 4]
[1, 4, 3, 2]
[2, 1, 3, 4]
[2, 4, 1, 3]
[2, 3, 1, 4]
[2, 4, 3, 1]
因为3和4不能放入列表的第一个插槽,所以所有以3或4开头的排列都将被删除。此外,4无法装入第三个插槽,因此第三个插槽中4的任何剩余布置都将被移除
这是我当前试图暴力解决问题的代码:
from itertools import permutations
x = [1, 2, 3, 4]
box = [2, 4, 3, 4] # this is the list we need to fit our arrangements into
counter = 0
for permutation in permutations(x):
foo = True
for i in range(len(permutation)):
if permutation[i] > box[i]:
foo = False
break
if foo:
counter += 1
print(counter)
它是有效的,但是因为我正在生成第一个列表的所有可能的排列,它非常慢,但我就是找不到一个算法。我意识到这基本上是一个数学问题,但我的数学不好。如果你把
x
倒过来排序,你可以试着找到每个元素可以放在盒子里的所有点,一次一个
在您的示例中:
- 4有两个点,它可以去
- 3有3个点,但你必须说明已经放置了“4”, 所以你有3-1=2可用
- 2有4个点,但你必须说明已经放置了两个点 (“4”和“3”),因此您有4-2=2可用
- 1有4个点,但您已经放置了3个点。。。so 4-3=1
import numpy as np
counter = 1
for i, val in enumerate(reversed(sorted(x))):
counter *= ( (val <= np.array(box)).sum() - i)
print(counter)
将numpy导入为np
计数器=1
对于i,枚举中的val(反转(排序(x)):
计数器*=((val我对计时进行了一些实验,以下是我的发现:
您的原始代码
每次运行约13569纳秒
过滤排列
范围(100)内的i的:
res=len(list(filter)(lambda perm:all([perm[i]你能在没有numpy库的情况下执行此操作吗?已添加。我的大脑中经常有pandas/numpy,所以只需默认设置为:)如果你在他的例子中仅用4个元素来衡量这一点,numpy版本就不会更快,尽管我文章中的第二个版本仍然比原始循环快3倍。我的假设是他们想要更长的列表,但如果他们的问题是他们需要多次执行这个较小的列表操作,那么optimi是正确的按原样放大会有帮助。我发布的第二个版本确实有帮助。如果你让列表有10个元素,我的第二个版本是8.75微秒,而随机示例是1.17秒。在200个元素时,它比我愿意等待的时间长约3毫秒。我认为分析时间复杂性比分析我的平均时间更有趣初始示例。例如,我的解决方案具有O(n!)
复杂性,因此它是所有解决方案中最糟糕的。
for i, val in enumerate(reversed(sorted(x))):
counter *= ( sum( ( val <= boxval for boxval in box)) - i)
for permutation in permutations(x):
foo = True
for i in range(len(permutation)):
if permutation[i] > box[i]:
foo = False
break
if foo:
counter += 1
for i in range(100):
res = len(list(filter(lambda perm: all([perm[i] <= box[i] for i in range(len(box))]), permutations(x))))
counter = 1
for i, val in enumerate(reversed(sorted(x))):
counter *= ((val <= np.array(box)).sum() - i)
def findPossiblities(possibleValues, box):
return not box or sum([findPossiblities([rem for rem in possibleValues if rem != val], box[1:]) for val in [val for val in possibleValues if val <= box[0]]])
findPossiblities(x, box)