如何以小于O(N ^ 2)的复杂度查找所有连续子数组的gcd

时间:2019-09-10 12:47:55

标签: python greatest-common-divisor

我需要找到一个非常大的数组的所有连续子数组的所有可能的gcd。我需要的解决方案少于O(N 2 )时间。

这是我对O(N ^ 2)的解决方案。

from math import gcd
lst = [5,3,5,8,9,4,5,6] # A very long list
gcds = {1:0,2:0,3:0,4:0}#  .....  All initialized with 0
for i in range(N):
    g = lst[i]
    for j in range(i+1,N):
        g = gcd(g,lst[j])
        if g== 1:
            gcds[1] += N-j
            break
        gcds[j] += 1

1 个答案:

答案 0 :(得分:1)

解决此问题的关键是GCD功能具有关联性。那是gcd(a, gcd(b, c)) == gcd(gcd(a, b), c)

确切有n(n+1)/2个连续的子数组,每个子数组都有一个GCD,可以像通过简单地获取相邻元素的GCD,然后对三角形中每一行的结果重复此操作来计算它们:

5 3 5 8 9 4 5 6
 1 1 1 1 1 1 1
  1 1 1 1 1 1
   1 1 1 1 1
    1 1 1 1
     1 1 1
      1 1
       1
from fractions import gcd
output = []
lst = [5,3,5,8,9,4,5,6]
while lst:
    o = []
    x = lst[0]
    for l in lst[1:]:
        o.append(gcd(l, x))
        x = l
    output.extend(o)
    lst = o
print output

得到[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]28

其复杂度为n(n+1)/2或O(n ^ 2)。让我们忽略那个n=len(input)-1

这也适用于其他示例

3 6 9 4
 3 3 1
  3 1
   1

该程序的结果为[3, 3, 1, 3, 1, 1]

使用Counter,可以输出直方图而不是列表:

from fractions import gcd
from collections import Counter
output = []
gcds = Counter()
lst = [3, 6, 9, 4]
while lst:
    o = []
    x = lst[0]
    for l in lst[1:]:
        v = gcd(l, x)
        gcds[v] += 1
        o.append(v)
        x = l
    lst = o
print gcds

打印Counter({1: 3, 3: 3})