数字总和可被 K 整除的子数组的数量

Posted

技术标签:

【中文标题】数字总和可被 K 整除的子数组的数量【英文标题】:number of subarrays where sum of numbers is divisible by K 【发布时间】:2012-07-31 02:39:07 【问题描述】:

给定一个数组,找出有多少这样的子序列(不需要是连续的),其中该子数组中的元素之和可以被 K 整除。

我知道一种复杂度为 2^n 的方法,如下所示。这就像找到 i=[0,n] 的所有 nCi 并验证 sum 是否可被 K 整除。 请提供类似线性/二次或 n^3 的伪代码。

static int numways = 0;
void findNumOfSubArrays(int  [] arr,int index, int sum, int K) 
        if(index==arr.length) 
                if(sum%k==0) numways++;
        
        else 
                findNumOfSubArrays(arr, index+1, sum, K);
                findNumOfSubArrays(arr, index+1, sum+arr[index], K);
        

【问题讨论】:

你提到的这种方法看起来更像是蛮力而不是分而治之,只是说 将原数组取模缩小到[0 .. (k-1)]的范围内,然后用动态规划计算组合的个数(一维是取模,另一维是您总结的元素数量)。 【参考方案1】:

输入 - 数组 A,长度为 n,自然数为 k。

算法:

构造数组 B:对于每个 1

现在我们可以使用动态规划了:

我们定义 D[i,j] = - B[i..n] 的最大子数组数,其元素的模 k 之和等于 j。

1

D[n,0] = if (b[n] == 0), 2. 否则为 1.

如果 j > 0:

D[n,j] = if (B[n] modulo k) == j, 大于 1。否则为 0。

对于 i

D[i,j] = maxD[i+1,j], 1 + D[i+1, D[i+1,(jB[i]+k) 模 k)]。

构造 D.

返回 D[1,0]。

整体运行时间:O(n*k)

【讨论】:

D[i,j] = maximum number of sub-arrays of - B[j..n] that the sum of its elements = j j 之一是i,不是吗? 我不明白你的问题 - i 代表起始子数组,j 代表我们想要的子数组的总和(当然是模 k)。 那不是台风吗?不应该是 B[i..n] 吗? :\ 对不起伙计们..我的意思只是子序列..这对子序列有用吗? 以上算法是针对子序列的。【参考方案2】:

实际上,如果 K 的范围和数组中的数字范围未知,我认为这个问题不可能在 O(n^3) 甚至多项式时间内解决。这是我的想法:

考虑以下情况:arr 中的 N 个数字类似于

[1,2,4,8,16,32,...,2^(N-1)]

,

这样,arr 的 2^N 个“子数组”(不需要连续)的总和正好是 [0,2^N) 中的所有整数

问其中有多少能被K整除,相当于问[0, 2^N)中有多少整数能被K整除。

我知道在上述情况下,答案可以像 (2^N-1)/K(或其他东西)一样直接计算出来。但是,如果我们只是随机更改 arr 中的几个(可能是 3?4?)数字,以在完美连续整数范围 [0,2^N)中“挖一些随机洞”,这看起来不可能无需遍历 [0,2^N) 中的几乎所有数字即可计算答案。

好吧,只是一些愚蠢的想法......可能是完全错误的。

【讨论】:

n 这里是数组的长度。他要求 n 的多项式时间,而不是你提到的任何其他事情 我的意思是:这个问题不能在 n 的多项式时间内解决 作为参考,可以看到上面barak提供的DP方案需要O(n*k),也就是说算法取决于K的大小。这是Pseudo-polynomial time的一个例子,不是 n 的多项式时间内的算法。 你是对的,但是如果你假设 k 是常数,并且 n 是数组的长度,那么上面的算法就是 O(n)。如果将n定义为输入的大小,则上述算法不是多项式的。【参考方案3】:

使用辅助数组A

1) 在接受输入时,将当前总计存储在相应的索引中(这在O(n) 中执行):

int sum = 0;
for (int i = 0; i < n; i++)

    cin >> arr[i];
    sum += arr[i];
    A[i] = sum;

2) 现在,

for (int i = 0; i < n; i++)
    for (int j = i; j < n; j++)
        check that (A[j] - A[i] + arr[i]) is divisible by k

你去:O(n^2)...

【讨论】:

子数组不一定像 OP 提到的那样连续。 所以你是说在 2^n 个子数组中不超过 n^2 个子数组可以被 k 整除? 我告诉了 Subarray 的解决方案...你们所说的 abt 是 Subsequence,所以您需要以更好的方式提出问题。 也许他用错了术语,但他写了“不需要连续”。

以上是关于数字总和可被 K 整除的子数组的数量的主要内容,如果未能解决你的问题,请参考以下文章

leetcode 974. 和可被 K 整除的子数组

可被 k 整除的子数组数

974. 和可被 K 整除的子数组

[LeetCode] 974. 和可被 K 整除的子数组 !!!

[LeetCode] 974. 和可被 K 整除的子数组 !!!

总和可被k整除的最长子序列[关闭]