【问题标题】:finding the maximum product of 2 primes below a given number找到给定数字以下的2个素数的最大乘积
【发布时间】:2015-11-18 22:13:36
【问题描述】:

给定一个数 N,我们如何找到最大 P*Q

我的(蛮力)尝试:

  • 找到所有素数 P 的列表 {P, N/P}
  • 找到素数 Q 的列表,使得 Q 是正下方的最大素数 上面列表中的 N/P
  • 从上面确定最大乘积 P*Q

虽然这种蛮力方法可行,但是否有正式(更明智)的解决方案来解决这个问题?

示例:N=27

√N = 5.196

Candidate primes: 2,3,5 --> [{2,13.5},{3,9},{5,5.4}] ->[{2,13},{3,7},{5,5}]

Solution: Max([2*13, 3*7, 5*5]) = 2*13 = 26

因此,蛮力解决方案有效。

更进一步,我们看到 Q_max = √N。

我们可以将我们的解决方案集优化为仅那些值 {P, N\2},其中 N\2 >= √N。

我选择了整数除法“\”,因为我们只对整数值感兴趣,而且整数除法确实比常规除法“/”快得多

问题简化为:

示例:N=27

√N = 5.196

Candidate P: 2,3 --> [{2,13},{3,9}] -->[{2,13},{3,7}]

(we drop {5,5} since N\P < √N i.e. 5 < 5.196)

Solution set: max([2*13, 3*7]) = 2*13 = 26

它可能看起来微不足道,但它只是消除了 1/3 的可能解决方案集。

我们可以添加其他巧妙的程序来进一步减少集合吗?

【问题讨论】:

  • 您提到了有问题的互质数,但您问过“P 和 Q 是质数吗?”。你需要素数还是互素数?
  • 这是一个已知的难题。如果你有效地解决它,你就可以破解 RSA 加密并变得富有和/或出名。
  • 任何两个(不相等的)素数总是互质的,这是多余的。那么,在 P==Q 的情况下,您是否禁止 P*Q?如果不是,那么标题中的“互质”必须去掉。
  • @JohnColeman P 和 Q 相同可能是允许的。如果没有“互质”这个词,它允许的。
  • @CharlesO 因为此方法按降序分解数字。所以只有两个质因数的第一个是最大的。 :)

标签: algorithm primes multiplication


【解决方案1】:

另一个蛮力尝试:

  1. 查找所有素数 p
  2. 从最小的 p 开始迭代数组,只要 p

如果有足够的内存可用(N/2 位),可以制作一个该大小的位数组。除第一个位置外,使用所有 TRUE 对其进行初始化。遍历位数组,计算您所在位置的倍数并将所有倍数设置为 false。如果下一个位置已经为假,则不需要重新计算它的所有倍数,它们已经设置为假。

因此找到所有素数是

a[1] := false;
m := n \ 2; // sizeof(a)
for i := 2 to m do
   a[i] := true;
for i := 2 to m do
   if a[i] then
     for j := 2*a[i] to m step a[i] do
       a[i*j] := false;

步骤 2) 也是

result := 0;
for i := 2 to √N do
  if not a[i] then continue; // next i;
  for j := (n \ i) downto i do
     if not a[j] then continue; // next j
     if a[j] * a[i] < N
        result :=  max(result, a[j] * a[i]);
        break; // next i;
  if result = N then break; // you are finished

我猜这可以进一步优化。你可以保持 (i,j) 知道这两个素数。

【讨论】:

  • 为什么选择P
  • 将其更正为 p N/2 都不能与另一个素数相乘并且仍然小于 N。
  • 更好的选择是P
  • 不适用于此算法。如果我取 p N/p} 以找到每个 p 的最大 q*p = 2,q 将始终
  • +1 很好的解释,尽管您可以使素数上的迭代更智能并在那里获得 O(n) 性能,请参阅我的答案。
【解决方案2】:

这类似于 @RalphMRickenback 所描述的,但具有更严格的复杂性界限。

他描述的素数查找算法是sieve of Erathostenes,它需要空间O(n),但时间复杂度O(n log log n),如果你想了解更多可以看维基百科上的讨论小心这个。

找到小于n // 2 的素数列表后,您可以一次扫描它,即具有 O(n) 复杂度,方法是让一个指针从开头开始,另一个指针在结尾。如果这两个素数的乘积大于您的值,请减小高指针。如果乘积较小,则将其与存储的最大乘积进行比较,并增加低位指针。

EDIT 正如 cmets 中提到的,素数扫描的时间复杂度在n 上优于线性,因为它仅在小于n 的素数上,所以 O (n / log n)。

这里是 Python 的完整实现,而不是伪代码:

def prime_sieve(n):
    sieve = [False, False] + [True] * (n - 1)

    for num, is_prime in enumerate(sieve):
        if num * num > n:
            break
        if not is_prime:
            continue
        for not_a_prime in range(num * num, n + 1, num):
            sieve[not_a_prime] = False

    return [num for num, is_prime in enumerate(sieve) if is_prime]

def max_prime_product(n):
    primes = prime_sieve(n // 2)

    lo, hi = 0, len(primes) - 1
    max_prod = 0
    max_pair = None

    while lo <= hi:
        prod = primes[lo] * primes[hi]
        if prod <= n:
            if prod > max_prod:
                max_prod = prod
                max_pair = (primes[lo], primes[hi])
            lo += 1
        else:
            hi -= 1
    return max_prod, max_pair

你的例子会产生:

>>> max_prime_product(27)
(26, (2, 13))

【讨论】:

  • 其实算法扫描阶段的时间复杂度是O(pi n) = O(n / log n ),因为扫描是针对小于 n 的素数而不是小于 n 的正整数。您可以通过缓存素数来提高算法的运行时间。
  • 非常正确,已编辑,谢谢!关于 O(n / log n) 如何与更常见的复杂性进行比较的任何线索或参考,例如O(n^k) 与 0
  • @Jaime Sieve 的 Eratosthenes 将找到所有小于 N/2 的素数。我相信这些素数中的大多数可能会被丢弃。我们将进一步受益的是一个有效的丢弃标准,以限制正在考虑的候选素数。
  • @Jaime:渐近地说,O(n / log n) 优于 O(n)。感谢您的客气话;也许您可以不时提供解决方案。甚至明天。
猜你喜欢
  • 2021-05-09
  • 1970-01-01
  • 2017-01-08
  • 2021-05-12
  • 1970-01-01
  • 1970-01-01
  • 2019-10-24
  • 2013-12-31
  • 2021-03-09
相关资源
最近更新 更多