number of subarrays where sum of numbers is divisible by K
给定一个数组,找出存在多少个这样的子序列(不需要是连续的),其中该子数组中的元素之和可被K整除。
我知道一种复杂度为2 ^ n的方法,如下所示。 就像找到所有i = [0,n]的nCi并验证和是否可以被K整除一样。
请提供伪代码,例如线性/二次或n ^ 3。
1 2 3 4 5 6 7 8 9 10 | 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); } } |
输入-长度为n的数组A,自然数为k。
算法:
- 构造数组B:对于每个1 <= i <= n:B [i] =(A [i]模K)。
现在我们可以使用动态编程了:
我们定义D [i,j] =-B [i..n]的子数组的最大数目,其子元素的模数之和等于j。
1 <= i <= n。 0 <= j <= k-1。
D [n,0] =如果(b [n] == 0),2。否则,1。
如果j> 0:
D [n,j] =如果(B [n]模k)== j,则大于1,否则为0。
对于i
D [i,j] = max {D [i + 1,j],1 + D [i + 1,D [i + 1,(j-B [i] + k)模k)]]}。
构造D。
返回D [1,0]。
总运行时间:O(n * k)
从根本上说,如果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)中的几乎每个数字。
好吧,只是一些愚蠢的想法...可能是完全错误的。
使用辅助数组
1)在输入时,将当前总计存储在相应的索引中(这在
1 2 3 4 5 6 7 | int sum = 0; for (int i = 0; i < n; i++) { cin >> arr[i]; sum += arr[i]; A[i] = sum; } |
2)现在,
1 2 3 | 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 |
你去了: