查找从a到b的数字不能被x到y整除

时间:2013-04-12 05:14:18

标签: python math set division modulo

这是我一直在思考的一个问题。

从a到b查找所有数字的最快方法是什么,这些数字不能被x到y中的任何数字整除?

考虑一下:

我想找到1到10之间不能被2到5整除的所有数字。 如果我在哪里使用线性方法,这个过程将变得极其缓慢; 像这样:

result = []
a = 1
b = 10
x = 2
y = 5
for i in range(a,b):
    t = False
    for j in range(x,y):
        if i%j==0:
            t = True
            break
    if t is False:
        result.append(i)
return result

有没有人知道使用比线性解决方案更少的计算时间来执行此操作的任何其他方法?

如果没有,任何人都可以看到这个可能如何更快地完成,因为我此时空白......

此致 约翰

[编辑]

该数字的范围是0到> 1,e + 100

这适用于a,b,x和y

2 个答案:

答案 0 :(得分:4)

您只需要检查可能除数范围内的素数值 - 例如,如果某个值不能被2整除,它也不会被2的任意倍数整除;同样适用于所有其他素数和素数倍数。因此,在您的示例中,您可以检查2, 3, 5 - 您不需要检查4,因为任何可被4整除的内容必须可以被2整除。因此,更快的方法是计算任何范围内的素数你感兴趣,然后简单地计算它们分成的值。

另一种加速是将您感兴趣的范围中的每个值添加到set:当您发现它可以被您的范围内的数字整除时,将其从集合中删除。然后,您应该只测试保留在集合中的数字 - 这将阻止您多次测试数字。

如果我们将这两种方法结合起来,我们就会发现我们可以创建所有值的set(所以在示例中,所有值都是1到10的集合),并简单地删除每个素数的倍数。你的第二个范围。

编辑:正如Patashu指出的那样,如果除以给定值的素数不在集合中,这将不会起作用。要解决此问题,我们可以对上述内容应用类似的算法:为set中的每个值创建值为[a, b]的{​​{1}},删除其所有倍数。因此,对于下面评论中给出的示例(使用set),我们从3开始并删除它在集合中的倍数 - 所以[3, 6]。因此,我们需要测试的剩余值将是6,这是我们在这种情况下想要的。

Edit2:这是一个非常糟糕的,糟糕的实现,尚未优化并且具有可怕的变量名称:

[3, 4, 5]

尝试使用这些数字进行原始实施。它需要>我的电脑上1分钟。此实现需要不到2秒。

答案 1 :(得分:3)

终极优化警告:不要过早优化。每当您尝试优化代码时,对其进行分析以确保其需要优化,并对要优化的相同类型的数据进行优化,以确认它是一种加速。几乎所有代码都不需要优化,只是给出正确的答案。

如果您正在优化小x-y和大a-b:

创建一个长度为x,x + 1,x + 2 ... y中最低公倍数的数组。例如,对于2,3,4,5,它将是60,而不是120。

现在使用布尔值填充此数组 - 最初为每个单元格填充false,然后对于x-y中的每个数字,填充数组中所有数字的倍数为true。

现在对于a-b中的每个数字,索引数组模数arraylength,如果为真,则跳过else,如果为false,则返回。

你可以更快地做到这一点,你可以从中删除x到y因子数,其中素数因子扩展是其他数字素数扩展的严格超集。我的意思是 - 如果你有2个,3个,4个,5个,4个是2 * 2的2的严格超集,那么你可以删除它,现在我们的数组长度只有30个。如3,4,5,6这样的东西然而,4是2 * 2,6是3 * 2 - 6是3的超集所以我们删除它,但4不是所有内容的超集,所以我们保留它.LCM是3 * 2 * 2 * 5 = 60做这种事情可以为大型ab提供一些加速,如果你需要的话,你可能不需要去阵列方向。

另外,请记住,如果您不打算每次都使用函数的整个结果 - 例如,有时候您只对最低值感兴趣 - 将其写为生成器而不是作为生成器功能。这样你可以调用它,直到你有足够的数字,然后停止,节省时间。