所有因子产品的计数小于最大值

时间:2013-07-25 00:51:15

标签: python algorithm permutation primes factors

我想列举一些整数因子的所有可能产品,只能达到某个最大值:

  • P((2, 3, 11), 10)会返回(2, 3, 4, 6, 8, 9)
  • P((5, 7, 13), 30)会返回(5, 7, 13, 25)

这似乎是树遍历,一旦达到最大值,树枝就会停止生长,但我不知道树枝数量的界限是什么。这个问题推荐使用什么算法或习惯用法?到目前为止我最接近的是itertools.product(),它似乎为每个输出集设置了固定数量的术语(例如2)。

对于上下文,我试图检查n的互质数字。在这种情况下,n本身是上限,因子列表是n的因子。我试着将这个问题概括一点。

3 个答案:

答案 0 :(得分:3)

我喜欢这种方法,它包括将输入列表中的所有元素乘以1,然后将所有结果乘以输入列表中的元素等,直到达到限制。

def signature_seq(signature, limit):
  products = set((1,))
  for factor in signature:
    new_products = set()
    for prod in products:
      x = factor * prod
      while x <= limit:
        new_products.add(x)
        x *= factor
    products.update(new_products)

  products.remove(1)
  return products

这应该做你想要的:

>>> print(sorted(signature_seq((2, 3, 11), 10)))
[2, 3, 4, 6, 8, 9]
>>> print(sorted(signature_seq((5, 7, 13), 30)))
[5, 7, 13, 25]

顺便说一下,如果给出一个以2开头的连续素数列表,那么这是一个smooth number生成器。

答案 1 :(得分:2)

这是使用生成器(和itertools.count)的解决方案:

from itertools import count

def products(numbers, limit):
    numbers = set(numbers)  # needs a set to pop from, not a tuple
    while numbers:
        n = numbers.pop()
        for r in (n ** e for e in count(1)):
            if r > limit:
                break
            yield r
            for p in products(numbers, limit / r):
                yield r * p

因为它是一个生成器,它返回一个迭代器 - 并且结果没有排序,所以对于你想要的特定输出,你可以这样称呼它:

>>> sorted(products((2, 3, 11), 10))
[2, 3, 4, 6, 8, 9]
>>> sorted(products((5, 7, 13), 30))
[5, 7, 13, 25]

答案 2 :(得分:0)

仅使用带有元组(2,3,4)的itertools的想法:

拥有多种笛卡儿产品:

(2,),(3,),(4,) # repeat 1
(2, 2), (2, 3), (2, 4), (3, 2), (3, 3), (3, 4), (4, 2), (4, 3), (4, 4) # repeat 2
...

对于每个元组,使用reduceoperator.mul以及起始值1,将它们相乘:

reduce(operator.mul, tuple, 1)

这将产生2级笛卡尔积的乘法:

[reduce(operator.mul,t,3) for t in itertools.product((1,2,3),repeat=2)]
>>>[3, 6, 9, 6, 12, 18, 9, 18, 27]

现在,我们需要增加repeat直到满足停止条件,例如:每次乘法都会产生大于top的结果。由于最重要的samllest值是2(因为11很多次只是1因此它不会计数)我们可以乘以2倍x而低于top 。因此:top/2 = x表示我们可以遍历range(1,top/2)

[reduce(operator.mul,t,1) for c in range(1,10/2) for t in itertools.product((1,2,3),repeat=2) if reduce(operator.mul, t, 1) < 10]

这会产生重复的值,所以我们将它们转换成一组:

set([reduce(operator.mul,t,1) for c in range(1,10/2) for t in itertools.product((1,2,3),repeat=2) if reduce(operator.mul, t, 1) < 10])

仅使用itertools可能会很麻烦,但解决方案看起来很漂亮。我确信它可以通过引入更好的停止条件来优化。最终代码如下所示:

注意:有一个素数定理,可以让您将停止条件优化为math.sqrt(top)

import math
def f(t,m):
    return set([reduce(operator.mul, t1, 1) for c in range(1,int(math.sqrt(m)) for t1 in itertools.product(t,repeat=c) if reduce(operator.mul,t1,1) < m])

f((2,3,4),10)
>>>set([2, 3, 4, 6, 8, 9])

希望这可能会给你另一个想法:)