Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 一个给定除数列表的有效逆因式分解_Python_Recursion_Permutation_Factorization - Fatal编程技术网

Python 一个给定除数列表的有效逆因式分解

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

给定一个数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_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) 4(x3) / | | \ 2(x3) 3(x2) 3 4(x1) / | 2 3(x1) 这相当快。在您的特定情况下,它只检查4个节点,而不是~30个节点。事实上,您可以证明它检查的节点数是绝对最小的。您可能得到的唯一改进是使用迭代而不是递归,我怀疑这会有多大帮助

第2部分:

现在,您只需生成结果中每个元素的排列。Python提供了直接在标准库中执行此操作的工具:

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) 4(x3) / | | \ 2(x3) 3(x2) 3 4(x1) / | 2 3(x1) 这相当快。在您的特定情况下,它只检查4个节点,而不是~30个节点。事实上,您可以证明它检查的节点数是绝对最小的。您可能得到的唯一改进是使用迭代而不是递归,我怀疑这会有多大帮助

第2部分:

现在,您只需生成结果中每个元素的排列。Python提供了直接在标准库中执行此操作的工具:

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//factorfrom 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, [])))