给定数字N,找到将其写为两个或更多个连续整数之和的方法的数量

时间:2010-12-27 06:05:17

标签: algorithm big-o dynamic-programming

这是标记为动态编程problem(给定数字N,找到将其写为两个或更多个连续整数之和的方法的数量)和示例15 = 7 + 8,1 + 2 + 3 + 4 + 5,4 + 5 + 6

我用这样的数学解决了:

a +(a + 1)+(a + 2)+(a + 3)+ ... +(a + k)= N

(k + 1)* a +(1 + 2 + 3 + ... + k)= N

(k + 1) a + k (k + 1)/ 2 = N

(k + 1)*(2 * a + k)/ 2 = N

然后检查如果N可以被(k + 1)和(2 * a + k)整除,那么我可以在O(sqrt(N))时间内找到答案

以下是我的问题,如何通过动态编程来解决这个问题?什么是复杂性(O)?

P.S:不好意思,如果这是一个重复的问题。我搜索了但我能找到

5 个答案:

答案 0 :(得分:1)

对于奇数 N ,此问题相当于查找N的除数不超过sqrt(N)。 (对于偶数 N ,有几个曲折。)如果您有权访问素数列表O(sqrt(N)/ln(N)),则该任务需要O(sqrt(N))

我不知道动态编程在这里有什么帮助。

答案 1 :(得分:1)

我们可以使用动态编程来计算所有K到N的1 + 2 + 3 + ... + K之和。sum[i]以下表示总和1 + 2 + 3 + ... +岛

sum = [0]
for i in 1..N:
  append sum[i-1] + i to sum

利用这些和,我们可以快速找到求和为N的所有连续整数序列。和i +(i + 1)+(i + 2)+ ... j等于sum[j] - sum[i] + 1。如果总和小于N,我们递增j。如果总和大于N,我们递增i。如果总和等于N,我们会增加计数器ij

i = 0
j = 0
count = 0
while j <= N:
  cur_sum = sum[j] - sum[i] + 1
  if cur_sum == N:
    count++
  if cur_sum <= N:
    j++
  if cur_sum >= N:
    i++

虽然有比使用这种动态编程解决方案更好的选择。可以使用公式k(k + 1)/ 2以数学方式计算sum数组,因此我们可以在不需要额外存储的情况下即时计算它。更好的是,因为我们只在每次迭代中将最终合并的和的端点移动至少1,所以我们可以通过添加/减去添加/删除的值来更快地计算它。 / p>

i = 0
j = 0
sum = 0
count = 0
while j <= N:
  cur_sum = sum[j] - sum[i] + 1
  if cur_sum == N:
    count++
  if cur_sum <= N:
    j++
    sum += j
  if cur_sum >= N:
    sum -= i
    i++

答案 2 :(得分:1)

被接受的答案很好,但是没有更好的方法。发布我的Java代码如下,以供参考。它可能很冗长,但是可以更清楚地解释这个想法。假设连续的整数都是正数。

private static int count(int n) {
    int i = 1, j = 1, count = 0, sum = 1; 
    while (j<n) {
        if (sum == n) { // matched, move sub-array section forward by 1
            count++; 
            sum -= i; 
            i++;
            j++;
            sum +=j; 
        } else if (sum < n) { // not matched yet, extend sub-array at end
            j++; 
            sum += j; 
        } else { // exceeded, reduce sub-array at start
            sum -= i; 
            i++; 
        }
    }
    return count;
}

答案 3 :(得分:0)

为了解决这个问题,我们将尝试[1,M]中所有连续整数的和,其中M来自M(M + 1)/ 2 = N。

int count = 0
for i in [1,M]
  for j in [i, M]
    s = sum(i, j) // s = i + (i+1) + ... + (j-1) + j
    if s == N 
       count++
    if s >= N
       break
return count
< p>

由于我们不希望在每次迭代中从头开始计算sum(i, j),我们将使用称为“memoization”的技术。让我们创建一个整数矩阵sum[M+1][M+1]并将sum[i][j]设置为i +(i + 1)+ ... +(j-1)+ j。

for i in [1, M]
  sum[i][i] = i

int count = 0 for i in [1, M] for j in [i + 1, M] sum[i][j] = sum[i][j-1] + j if sum[i][j] == N count++ if sum[i][j] >= N break return count

复杂性显然是O(M ^ 2),即O(N)

答案 4 :(得分:0)

1)对于n> = 0的整数,从0到n的整数之和为n *(n + 1)/ 2。这很经典:首先写下这个总和:     S = 0 + 1 + ... + n 然后像这样:     S = n +(n-1)+ ... + 0 你看到2 * S等于(0 + n)+(1 + n-1))+ ... +(n + 0)=(n + 1) n,所以S = n < / em>(n + 1)/ 2的确如此。 (众所周知,但我希望我的答案是自成一体的。)

2)从1开始,如果我们注意到cons(m,n)和m +(m + 1)+ ...(n-1)+ n,则posiive之间的整数的连续和(即> = 0)使得1&lt; = m&lt; = n我们看到: cons(m,n)=(0 + 1 + ... + n) - (0 + 1 + ... +(m-1))从1给出: cons(m,n)= n *(n + 1)/ - m(m-1)/ 2

3)然后将问题重新编写如下:在N = cons(m,n)形式中我们用多少种方式写入N,其中m,n整数使得1 <= m&lt; = n?如果我们有N = cons(m,n),这相当于m ^ 2 - m +(2N -n ^ 2 -n)= 0,即实数多项式T ^ 2 - m +(2N -n) ^ 2 -n)有一个真实的根,m:它的判别式delta必须是一个正方形。但我们有:

delta = 1 - 3*(2*N - n^2 - n)

此delta是一个必须是正方形的整数。因此存在整数M,使得:

delta = 1 - 3*(2*N - n^2 - n) = M^2

M^2 = 1 - 6*N + n(n+1)

n(n + 1)总是可以分为2(例如,从开始就是我们的S的2倍,但这里有一个更微不足道的原因,在连续的整数中,一个必须是偶数),因此M ^ 2是奇怪,暗示M必须是奇数。

4)重写或上一个等式为:

n^2 + n + (1-6*N - M^2) = 0

这表明实数多项式X ^ 2 + X +(1-6 * N - M ^ 2)具有实数零,n:因此其判别式γ必须是正方形,但是:

gamma = 1 - 4*(1-6*N-M^2)

并且这必须是正方形,因此在这里再次存在整数G,使得

G^2 = 1 - 4*(1-6*N-M^2)

G^2 = 1 + 4*(2*N + m*(m-1))

表明,由于M是奇数,G也是奇数。

5)减法M ^ 2 = 1 - 4 *(2 * N - n *(n + 1))到G ^ 2 = 1 + 4 *(2 * N + m * (m-1)))得到:

G^2 - M^2 = 4*(2*N + m*(m-1)) + 4*(2*N -n*(n+1))
          = 16*N + 4*( m*(m-1) - n*(n+1) )
          = 16*N - 8*N (because N = cons(m,n))
          = 8*N

最后这可以改写为:

(G-M)*(G+M) = 8*N, that is

[(G-M)/2]*[(G+M)/2] = 2*N

其中(G-M)/ 2和(G + M)/ 2是整数(G-M和G + M是偶数,因为G和M是奇数)

6)因此,在每种方式将N写为cons(m,n),我们可以将一种方式(并且只有一种方式,因为M和G唯一确定)与因子2相关联* N到乘积x * y,其中x =(GM)/ 2且y =(G + M)/ 2其中G和M是两个奇数整数。由于G = x + y和M = -x + y,因为G和M是奇数,我们看到x和y应该具有相反的奇偶性。因此,在x和y中,一个是偶数,另一个是奇数。因此2 * N = x * y其中x和y中,一个是偶数而另一个是奇数。让c是x和y中的奇数,d是偶数。然后2 * N = c * d,因此N = c *(d / 2)。因此,只要N = cons(m,n),c是奇数除N,并且由N唯一确定。相反,只要N有一个奇数除数,就可以对所有这些东西进行逆向工程以找到n和m。

7) * 结论:写作方式的数量之间存在一对一的对应关系N = cons(m,n)(这是写N的方式的数量)作为连续整数的总和,如我们所见)和N的奇数除数。 *

8)最后,我们要寻找的数字是n的奇数除数。 我想用DP或其他方法解决这个问题比解决前一个问题更容易。