Python 一个给定除数列表的有效逆因式分解
给定一个数n和一个除数a的列表,我如何有效地找到所有的除数组合,当它们相乘时,就会产生这个数 e、 g 输出:Python 一个给定除数列表的有效逆因式分解,python,recursion,permutation,factorization,Python,Recursion,Permutation,Factorization,给定一个数n和一个除数a的列表,我如何有效地找到所有的除数组合,当它们相乘时,就会产生这个数 e、 g 输出: [[3, 2, 2], [2, 3, 2], [2, 2, 3], [4, 3], [3, 4]] 这就是我迄今为止所做的工作,我根据stackoverflow上的许多find prime Factoriation问题中的一个进行了改编: def products(n, A): if n == 1: yield [] for each_divi
[[3, 2, 2],
[2, 3, 2],
[2, 2, 3],
[4, 3],
[3, 4]]
这就是我迄今为止所做的工作,我根据stackoverflow上的许多find prime Factoriation问题中的一个进行了改编:
def products(n, A):
if n == 1:
yield []
for each_divisor in A:
if n % each_divisor == 0:
for new_product in products(n // each_divisor, A):
yield new_product + [each_divisor]
这段代码似乎工作正常,但速度非常慢,如果我试图使用memoization将一个作为元组传递给函数以避免不可修复的类型错误,那么代码就不会提供正确的结果
关于如何提高该代码的效率,有什么建议吗
我尝试的记忆代码如下所示:
class Memoize:
def __init__(self, fun):
self.fun = fun
self.memo = {}
def __call__(self, *args):
if args not in self.memo:
self.memo[args] = self.fun(*args)
return self.memo[args]
@Memoize
def products(n, A): [as above]
使用上述定义的参数n调用函数时,A:
如果没有记忆,相同代码的输出为:
[[3, 2, 2], [2, 3, 2], [2, 2, 3], [4, 3], [3, 4]]
请注意,其他记忆功能(例如来自functools包@functools.lru_cachemaxsize=128)也会导致相同的问题。您可以将问题分解为递归部分以查找所有唯一的组合,以及一部分以查找每个排列的组合,而不是使用记忆功能。这将大大减少您的搜索空间,只会改变实际可行的选项 为了实现这一点,应该对一个问题进行排序 第1部分: 在可用的可能分解图上执行DFS。通过仅选择每个因子大于或等于其前导因子的顺序,向下截断冗余分支的搜索。例如: 12 / | \ / | \ / | \ 2(x6) 3(x4)
from itertools import chain, permutations
chain.from_iterable(map(permutations, products(n, A)))
您可以将其放入最后一系列产品中,如下所示:
运行listproducts12时,A显示我的机器有20-30%的改进,从5.2µs到4.0µs。使用更复杂的示例(如listproducts2*3*4*5*5*7*11、[2,3,4,5,6,7,8,9,10,11,12,14,22])运行时,显示了更显著的改进:7毫秒比42毫秒
第2b部分:
您可以使用类似于“无耻插头”中所示的方法,过滤掉由于重复因素而发生的重复排列。为了适应我们总是处理排序整数的初始列表这一事实,可以这样写:
def perm_dedup(tup):
maximum = (-1,) * len(tup)
for perm in permutations(tup):
if perm <= maximum: continue
maximum = perm
yield perm
计时非常支持这种完整的方法:对于问题,5.2µs vs 4.9µs;对于长示例,6.5 ms vs 42 ms。事实上,如果说有什么区别的话,避免重复排列似乎会进一步减少时间
TL;博士
更高效的实现,只使用标准库,只搜索唯一因子分解的唯一排列:
from itertools import chain, permutations
def perm_dedup(tup):
maximum = (-1,) * len(tup)
for perm in permutations(tup):
if perm <= maximum: continue
maximum = perm
yield perm
def products(n, A):
A = sorted(set(A))
def inner(n, A, L):
for i in range(len(A)):
factor = A[i]
if n % factor: continue
k = n // factor
if k < factor:
if k == 1:
yield L + [factor]
elif n in A:
yield L + [n]
break # Following k guaranteed to be even smaller
# until k == 1, which elif shortcuts
yield from inner(k, A[i:], L + [factor])
yield from chain.from_iterable(map(perm_dedup, inner(n, A, [])))
您可以将问题分解为一个递归部分来查找所有唯一的组合,而不是使用记忆,以及一个部分来查找每个排列的组合。这将大大减少您的搜索空间,只会改变实际可行的选项 为了实现这一点,应该对一个问题进行排序 第1部分: 在可用的可能分解图上执行DFS。通过仅选择每个因子大于或等于其前导因子的顺序,向下截断冗余分支的搜索。例如: 12 / | \ / | \ / | \ 2(x6) 3(x4)
from itertools import chain, permutations
chain.from_iterable(map(permutations, products(n, A)))
您可以将其放入最后一系列产品中,如下所示:
运行listproducts12时,A显示我的机器有20-30%的改进,从5.2µs到4.0µs。使用更复杂的示例(如listproducts2*3*4*5*5*7*11、[2,3,4,5,6,7,8,9,10,11,12,14,22])运行时,显示了更显著的改进:7毫秒比42毫秒
第2b部分:
您可以使用类似于“无耻插头”中所示的方法,过滤掉由于重复因素而发生的重复排列。为了适应我们总是处理排序整数的初始列表这一事实,可以这样写:
def perm_dedup(tup):
maximum = (-1,) * len(tup)
for perm in permutations(tup):
if perm <= maximum: continue
maximum = perm
yield perm
计时非常支持这种完整的方法:对于问题,5.2µs vs 4.9µs;对于长示例,6.5 ms vs 42 ms。事实上,如果说有什么区别的话,避免重复排列似乎会进一步减少时间
TL;博士
只使用
标准库和仅搜索唯一因子分解的唯一排列:
from itertools import chain, permutations
def perm_dedup(tup):
maximum = (-1,) * len(tup)
for perm in permutations(tup):
if perm <= maximum: continue
maximum = perm
yield perm
def products(n, A):
A = sorted(set(A))
def inner(n, A, L):
for i in range(len(A)):
factor = A[i]
if n % factor: continue
k = n // factor
if k < factor:
if k == 1:
yield L + [factor]
elif n in A:
yield L + [n]
break # Following k guaranteed to be even smaller
# until k == 1, which elif shortcuts
yield from inner(k, A[i:], L + [factor])
yield from chain.from_iterable(map(perm_dedup, inner(n, A, [])))
张贴你的备忘录代码。如果这是您想要的,并且它工作不正常,那么它将与失败的测试用例完美结合。当然,现在就编辑@KennyOstrom我添加了memoization示例我注意到memoize似乎不能很好地处理来自这个生成器函数的迭代器返回。现在就开始起草答案,张贴你的回忆录代码。如果这是您想要的,并且它工作不正常,那么它将与失败的测试用例完美结合。当然,现在就编辑@KennyOstrom我添加了memoization示例我注意到memoize似乎不能很好地处理来自这个生成器函数的迭代器返回。现在起草答案好吧,这太棒了,不仅是为了代码,也是为了解释。非常感谢你的帮助。我将稍微处理一下代码,以确保我理解了所有内容。我认为您的两种解决方案都缺少一些特定的案例,我现在正试图理解其中的原因。例如,示例:n=200,A=[10,20]应导致解决方案[[10,20],[20,10]],但它返回空值list@Fraccalo. 我错过了几个案子。将修复shortly@Fraccalo. 我已经解决了主要问题。当n//factor
from itertools import chain, permutations
def perm_dedup(tup):
maximum = (-1,) * len(tup)
for perm in permutations(tup):
if perm <= maximum: continue
maximum = perm
yield perm
def products(n, A):
A = sorted(set(A))
def inner(n, A, L):
for i in range(len(A)):
factor = A[i]
if n % factor: continue
k = n // factor
if k < factor:
if k == 1:
yield L + [factor]
elif n in A:
yield L + [n]
break # Following k guaranteed to be even smaller
# until k == 1, which elif shortcuts
yield from inner(k, A[i:], L + [factor])
yield from chain.from_iterable(map(perm_dedup, inner(n, A, [])))