【问题标题】:Iterate all coprime pairs using constant space?使用恒定空间迭代所有互质对?
【发布时间】:2017-05-30 00:19:11
【问题描述】:

我可以按照维基百科上列出的三叉树算法生成所有互质数对: https://en.wikipedia.org/wiki/Coprime_integers

快点:

Start with two coprime branches: (2,1), (3,1), then iterate:
Branch 1: (2m-n,m)
Branch 2: (2m+n,m)
Branch 3: (m+2n,n)

但是,每生产一对(例如打印,或者不保存在内存中),使用的空间将增加三倍。

这可能是haskell中的一个解决方案: Generating sorted list of all possible coprimes

但我在 python 中寻找一些东西,它没有惰性求值或无限列表。

【问题讨论】:

  • 请澄清:您想要与 Haskell 问题中相同的限制吗? The first element in each pair must be less than the second. The sorting must be done in ascending order -- by the sum of pair's elements; and if two sums are equal, then by the pair's first element. 如果是这样,您想在算法中交换这些对。 Python 确实有无限的生成器,可能就像你的“无限列表”。您是想避免“增长三倍”的问题,还是只想要简单的 Python 代码?
  • “但我在 python 中寻找一些东西,它没有惰性求值或无限列表。” Python 有生成器(惰性生成值)和函数(尤其是在itertools) 会产生潜在的无限序列。
  • 我不是在寻找 haskell 解决方案的限制,我应该这么说。无论懒惰/无限的术语如何,任何惯用的 python 解决方案都可以工作。

标签: python algorithm primes ternary-tree


【解决方案1】:

这使用对数空间,也许这样就足够了?它是线性时间(使用 O(k) 时间来产生前 k 对)。

def coprimes():
    yield (2, 1)
    yield (3, 1)
    for m, n in coprimes():
        yield (2*m - n, m)
        yield (2*m + n, m)
        yield (m + 2*n, n)

您可以在 David Eppstein 的这些文章中阅读有关此类自递归生成器的更多信息:

展示前 20 对的演示:

>>> pairs = coprimes()
>>> for _ in range(20):
        print(next(pairs))

(2, 1)
(3, 1)
(3, 2)
(5, 2)
(4, 1)
(5, 3)
(7, 3)
(5, 1)
(4, 3)
(8, 3)
(7, 2)
(8, 5)
(12, 5)
(9, 2)
(7, 4)
(9, 4)
(6, 1)
(7, 5)
(13, 5)
(11, 3)

演示第 十亿 对,这需要我的 PC 大约 4 分钟,而 Python 进程的内存使用量保持在任何 Python 进程至少需要我的 9.5 MB 基线。

>>> from itertools import islice
>>> next(islice(coprimes(), 10**9-1, None))
(175577, 63087)

【讨论】:

  • 这更优雅,应该被接受!信息链接也。
  • 是的,谢谢,这是一个优雅的解决方案,我不知道您可以使用迭代器来做到这一点。
  • 美丽。我流下了喜悦的泪水。
【解决方案2】:

公认的 Haskell 解决方案的 Python 版本

def find_coprimes():
    l = 1
    while True:
        i = 2
        while i < l-i:
            if gcd(i, l-i) == 1:
                yield i, l-i
            i += 1
        l += 1

只买几个:

iterator = find_coprimes()
for i in range(10):
    print(next(iterator))

输出:

(2, 3)
(2, 5)
(3, 4)
(3, 5)
(2, 7)
(4, 5)
(3, 7)
(2, 9)
(3, 8)
(4, 7)

【讨论】:

    【解决方案3】:

    该问题没有说明生成的互质数对的条件(例如,其中一个数字是否在特定范围内?)。不过,我发现以下两个示例很有趣(都需要恒定空间)。

    首先考虑Farey sequence,这里是Python 3中的一个例子:

    a, b, c, d = 0, 1, 1, n
    while c <= n:
        k = (n + b) // d
        a, b, c, d = c, d, k * c - a, k * d - b
        print(a, b)
    

    它将枚举所有互素对 a, b 与 1

    第二个例子是一种好奇心,使用基于Calkin–Wilf tree的想法,你可以无限地枚举所有互质数对。好吧,至少在数学上,在实践中你只受到你能够在内存中表示的数字的限制。无论如何,这是一个 Python 3 示例:

    a, b = 0, 1
    while True:
        a, b = b, 2*(a//b) * b - a + b
        print(a, b)
    

    如果您想找到一些满足某些属性的有理数的示例,但您不知道界限,这可能会很方便。当然,您可以尝试所有可能的自然数对,但这会直接生成互质数对。

    【讨论】:

      猜你喜欢
      • 2020-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-20
      • 1970-01-01
      相关资源
      最近更新 更多