一个数的质因数的乘积,小于那个数

问题描述

首先,我为标题道歉,我不知道如何用语言表达我的问题。嗯,这里是:

对于大于 1 的整数 a,令 Fa 的素因数的排序列表。我需要找到所有元组 c(填充为整数),这样每个元组的长度等于 F(F[0] ** c[0]) * (F[1] ** c[1]) * (...) < a 的大小。我应该补充一点,我是用 Python 编写的。

示例:

a = 60
F = [2,3,5]

# expected result:

C = {(0,0),(0,1),2),1,2,(1,(2,(3,(4,(5,0)}

我使用 itertools.product() 生成了这个结果,具体来说:

m = math.floor(round(math.log(a,min(F)),12))
for i in itertools.product(range(m + 1),repeat=len(F)):
    if math.prod([F[j] ** i[j] for j in range(len(F))]) < a: print(i)

我认为它有效,但效率低下。例如数字 5 只出现在一个元组中,但被检查了很多次!有没有办法让它更快?我会使用多个 while 循环(使用 break 语句),但由于我不知道 F 的长度是多少,我认为这是不可能的。

解决方法

您所有的 range 限制仅基于 min(F)。让我们针对 log(a,factor) 自定义每个以减少案例:

from math import ceil,log,prod
from itertools import product

a = 60
F = [2,3,5]

ranges = [range(0,ceil(log(a,factor))) for factor in F]

C = []

for powers in product(*ranges):
    if prod(F[i] ** power for i,power in enumerate(powers)) < a:
        C.append(powers)

print(C)

根据我的测量,您的代码生成了 216 个测试用例,得出 25 个结果,但上面的代码只生成了这些测试用例的 1/3。

,

您可以使用生成器遍历所有“有效”元组,如下所示:

def exponent_tuples(prime_factors,limit):
    def next_tuple(t):
        n = math.prod(f ** tt for f,tt in zip(prime_factors,t))
        for idx,(f,tt) in enumerate(zip(prime_factors,t)):
            n *= f
            if n < limit:
                return (0,) * idx + (tt + 1,) + t[idx + 1 :]
            n //= f**(tt+1)
        return None

    t = (0,) * len(prime_factors)
    while t is not None:
        yield t
        t = next_tuple(t)


for t in exponent_tuples([2,5],60):
    print(t)

这里的想法基本上是增加元组条目,例如数字的数字,并让相应的数字滚动到零并在达到定义的限制时携带 1。

我很确定这正是你想要的,除了它产生元组的顺序(可以通过修改 next_tuple 函数进行调整)

编辑:稍微简化代码

,

几乎熟的命题会是这样的(shell执行)

>>> max_exponents(42,[2,7])
[5,1]
>>> #pick 2
>>> max_exponents(42//2**2,[3,7])
[2,1]
>>> #pick 1
>>> max_exponents(42//(2**2*3**1),[7])
[0]

我快完成了。这将适应任何数量的因素!

,

不知何故你的命题简化为这个(更易读的形式?)

import math as m 
import pprint

a = 60
prime_factors = [2,5]

exponents =list(map(lambda x:m.floor(m.log(a,x)),prime_factors))
rez = []
for i in range(exponents[0]+1):
    for j in range(exponents[1]+1):
        for k in range(exponents[2]+1):
            if 2**i*3**j*5**k <= a:
                rez.append((i,j,k))
pprint.pprint(rez)

并且您想知道是否有一种方法可以使 if 更快(测试更少)。所以我们不再是在实现方面,而是在概念(算法)方面?

例如,一旦选择了第一个指数 c[0],下一个应该在 a//(2**c[a]) 中的一个拟合中选择,因为我猜是另一个回答者提出的

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...