请注意,除数必须唯一
所以32有1个唯一素因子[2],40有[2,5]等等。
给定范围[a,b],a, b <= 2^31
,我们应该找到此范围内有多少个唯一除数的数量。
我能想象的最好的算法是改进的 Eratosthenes Sieve ,其数组计算一个数字有多少素因子。但它不仅是O(n),在这样的范围内是不可接受的,而且在记忆方面也非常低效。
解决这个问题的最佳算法是什么?有这样的算法吗?
答案 0 :(得分:1)
我将在类似Python的伪代码中写出第一个想法。首先要了解您最多可能需要的主要因素:
p = 1
i = 0
while primes[i] * p <= b:
p = p * primes[i]
i = i + 1
这仅使用 b ,而不是 a ,因此您可能需要减少实际素因子的数量。但由于上述结果最多为9(因为前10个素数的乘积已超过2 31 ),您可以想象一次从这最大值一步下降:
cnt = 0
while cnt == 0:
cnt = count(i, 1, 0)
i = i - 1
return cnt
所以现在我们需要实现这个函数count
,我以递归方式定义它。
def count(numFactorsToGo, productSoFar, nextPrimeIndex):
if numFactorsToGo > 0:
cnt = 0
while productSoFar * primes[nextPrimeIndex] <= b:
cnt = cnt + count(numFactorsToGo - 1,
productSoFar * primes[nextPrimeIndex],
nextPrimeIndex + 1)
nextPrimeIndex = nextPrimeIndex + 1
return cnt
else:
return floor(b / productSoFar) - ceil(a / productSoFar) + 1
这个功能有两种区分。在第一种情况下,您还没有达到所需数量的素因子。所以你在另一个素数中相乘,它必须大于迄今为止已包含在产品中的最大素数。您可以通过从下一个素数的给定索引开始来实现此目的。您可以为所有这些递归调用添加计数。
第二种情况是您已达到所需数量的素因子。在这种情况下,您希望计算所有可能的整数 k ,使 a ≤ k ∙ p ≤ b'/ em>的。哪个很容易翻译成⌈ a / p ⌉≤ k ≤⌊ b / p ⌋所以计数将是⌊ b / p ⌋ - ⌈ a / p ⌉+ 1。实际实现我不使用浮点除法floor
或ceil
,而是为了性能而使用截断整数除法。所以我可能会把这一行写成
return (b // productSoFar) - ((a - 1) // productSoFar + 1) + 1
正如现在所写,您需要预先提供最多2 31 的primes
数组,这将是105,097,565个数字according to Wolfram Alpha的列表。这将导致相当大的内存需求,并且还会使外部循环(其中productSoFar
仍然很小)迭代大量的素数,这些素数将在以后不再需要。
您可以做的一件事是更改循环结束条件。而不仅仅是检查添加一个素数并不会使产品超过 b ,您可以检查是否可以在不超过的情况下包含产品中的下一个primesToGo
素数b'/ em>的。如果素因子的总数很大,这将允许您提前结束循环。
对于少数主要因素,事情仍然很棘手。特别是如果你有一个非常窄的范围[ a , b ]那么具有最大素因子数的数字可能是一个很大的素数因子乘以非常小的素数的乘积。考虑例如[2147482781,2147482793]。该区间包含4个具有4个不同因子的元素,其中一些包含相当大的素因子,即
因为直到sqrt只有4,792个素数(2 31 ),其中最大的46,337(适合16位无符号整数)。可以预先计算那些,并使用它来计算范围中的每个数字。但这又意味着在范围内迭代。这对小范围有意义,但不适用于大范围。
所以也许您需要预先区分这些情况,然后相应地选择算法。我不知道如何将这些想法结合起来 - 但是。如果其他人这样做,请随意扩展这篇文章或在此基础上撰写自己的答案。