子树在Segment树中的范围内可被三整除

时间:2015-01-05 16:02:49

标签: arrays algorithm binary-tree

我有一个由十进制数字组成的数组。基本上,我必须查询在给定范围内,当被视为十进制数时,有多少连续子数组可被3整除。

我使用的基本事实是,如果数字的总和可以被3整除,则数字可以被3整除。因此,感觉就像是一个修正形式的范围而不是一个总和即分段树问题。我正在使用自下而上的方法来构建段树,在该树中我在每个节点中放置了所需子阵列的计数器。但是,我遇到了导致零的问题。

任何人都可以帮助我。

2 个答案:

答案 0 :(得分:1)

可以在O(N)运行时复杂度中实现。我用Python编写了算法,看看代码:

s = [0, 0, 0]
arr = [0, 3, 0, 3]
count_map = [0]*(len(arr)+1)

for i,n in enumerate(arr):
    r = n % 3
    s = [s[(3 + (j - r))%3] for j in [0, 1, 2]]
    s[r] += (0 if n == 0 else 1)
    count_map[i+1] = count_map[i] + s[0]

print(count_map[len(arr)])

上面的算法打印4.要获得范围[i,j](包含i和j)的计数,请执行:count_map[j+1] - count_map[i]

这是JsFiddle试用它的链接。 http://jsfiddle.net/Lt7aP/179/

说明

对于可被3整除的数字;所有数字的总和必须可以被三整除。因此,我们可以应用基本模数学和映射变量来查找可被3整除的所有子数组。更多细节:

a = [1, 5]
m = [1 % 3, 5 % 3] = [1, 2]
Therefore [1, 5] ie. 15 is divisible as summations of its modulus [1, 2] is divisible by 3

想法是将数字的总和打破为剩余部分的总和3.上述算法中的s跟踪在当前的for-loop迭代中产生余数0,1,2的连续子数组的数量。

例如:在i = 3时,s [0]是范围(0,i-1)内的连续子阵列的数量,使得其3的余数为0(基本上可被3整除)。重要的更新步骤是:

s = [s[(3 + (j - r))%3] for j in [0, 1, 2]]

基本上,如果在当前迭代中,元素的余数为2,那么我可以使用具有余数1的连续子数组来生成具有余数0的子数组,依此类推。如果当前元素为0,那么我们可以忽略s [0]计数的更新或仅保留先前的计数。

答案 1 :(得分:0)

您可以通过动态编程解决此问题,并忽略前导零的数字,如下所示。令A(n,0),A(n,1),A(n,2)为在位置n结束的数字的计数,其不具有前导零,其中A(n,j)计数的数量这样的数字在除以3时给出j的余数。在给定A(n-1,j)的值的情况下,看到如何根据增加的n按递增顺序计算A(n,j)是相当简单的,因为除以3时数字的余数与其数字之和的余数相同。那么所有n的所有A(n,0)的总和就会给出你的答案。如果您想了解更多详情,请与我们联系。