【问题标题】:number of subarrays where sum of numbers is divisible by K数字总和可被 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)]的范围内,然后用动态规划计算组合的个数(一维是取模,另一维是您总结的元素数量)。

标签: algorithm optimization recursion dynamic-programming


【解决方案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] = max{D[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,所以您需要以更好的方式提出问题。
  • 也许他用错了术语,但他写了“不需要连续”。
猜你喜欢
  • 2013-05-12
  • 2012-10-16
  • 1970-01-01
  • 2020-06-26
  • 2015-12-22
  • 1970-01-01
  • 2013-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多