区分n个数,使得和等于N.

时间:2017-09-19 09:22:37

标签: algorithm

假设我想在1到N的范围内找到n个不同的数字,以便它们的和等于N.

n = 3, N = 10: the numbers will be (2, 3, 5);
n = 4, N = 10: the numbers will be (1, 2, 3, 4).

虽然找出这个问题的所有可能组合将需要指数时间,但我正在寻找“最小”组合,即最大数字是最小的。例如,

n = 4, and N = 12的情况下,(6, 3, 2, 1) and (5, 4, 2, 1)都可以作为解决方案,但我只对(5, 4, 2, 1)感兴趣。

对于这个问题,是否会有一个具有更好时间复杂度的算法?我听说过对数合并,但不知道如何在这里应用。

如果需要指明问题的任何细节,请告诉我。总是,任何帮助都将非常感激。

4 个答案:

答案 0 :(得分:7)

这个问题有一个简单的贪婪算法。

首先,有n个元素按升序排列,为了使它们不同,每个元素应该比其前一个元素大至少一个。

所以,我们有

1, 2, 3 ... , n

现在,所有n号码的总和为n*(n + 1)/2

剩下的是left = N - n*(n + 1)/2

为了使最后一个元素尽可能小,我们需要将left差异分散到所有数字

所以,我们有

1 + left/n, 2 + left/n, ..., n + left/n

如果left % n != 0,我们只需要在最后left % n元素中添加额外的1。

注意:如果N < n*(n + 1)/2,则没有解决方案

示例:

因此,对于n = 4且N = 12

First, we start with

1, 2, 3, 4

left = 12 - (4*5/2) = 2

So, now we have

1 + (2/4), 2 + (2/4), 3 + (2/4), 4 + (2/4) = 1, 2, 3, 4

As left % n = 2
Finally, we have

1, 2, 3 + 1, 4 + 1 = 1, 2, 4, 5

类似地,对于n = 3,N = 10

First, we start with

1, 2, 3

left = 10 - (3*4/2) = 4

So, now we have

1 + (4/3), 2 + (4/3), 3 + (4/3) = 2, 3, 4

As left % n = 1
Finally, we have

2, 3, 4 + 1 = 2, 3, 5

伪码,时间复杂度O(n)

int[]result = new int[n];
int left = N - n*(n + 1)/2;

for(int i = 0; i < n; i++){
    result[i] = i + 1 + left/n;
    if(i >= n - (left % n)){//Add extra one for last left % n elements
        result[i]++;
    }
}
return result;

答案 1 :(得分:0)

我们假设您有一个功能f(n, N, sum) - 它将返回结果,该结果将显示从n范围内1获取N元素的可能性总结为sum

至少现在您可以确定解决方案是否存在,只需调用f(n, N, N)

让我们说对于给定的nNsum,问题p(n,N,sum)有一个解决方案,x是最小的结果中的数字。然后问题p(n',N',sum')n'=n-1N'=x-1sum'=sum-x也应该有一个解决方案。问题p(0,N,0)总是有一个解决方案,它是归纳的基础。

函数f(n, N, sum)实际上会返回范围x1的最小数字N,它可以是解决方案的一部分(否则它应该返回-1或表示解决方案缺席的事情)。我们可以尝试1N的每个号码作为x,并检查f(n - 1, x - 1, sum - x)是否有解决方案。

这里的关键是使用 memoization 以便不多次计算相同的功能。记得发现x。记住每个可能的输入组合最多需要O(n * N * N)个空间和相同的O(n * N * N)时间来计算。此外,如果sum>N*(N+1)/2我们可以立即修剪此类电话,则无法解决问题。这是多项式时间/空间复杂度,优于指数。

答案 2 :(得分:0)

让我们尝试解决问题,假设我们在[1,N]之间有n个不同的数字。什么是最小可能总和,它将是前n个自然数的总和,即

1 + 2 + 3 + 4 + ... + n

可能的最大数量为

(N-n+1) + (N-n+2) + (N-n+3) + ... + (N-n+n)
  

注意可以使用n个数字

来计算最小值和最大值之间的总和

现在,检查值是否可行,我们可以做到。假设我们将数字1加到n。当前总和 S 等于

S = 1 + 2 + ... + n

如果我将x添加到每个元素,它将成为

S = 1 + 2 + ... + n + x*n <= N

如果我们选择最大可能的x,那么通过从最大值开始向所有数字添加1个元素直到达到所需的总和(即最多n-1个数字),可以得到总和。这将给我一个有效的答案。

所以如果答案可能就是

  1. 从1到n
  2. 中取元素
  3. 将x添加到每个元素
  4. 从最大数字继续加1直到达到总和

答案 3 :(得分:0)

这几乎可以立即计算出来。答案总是看起来像是以N/n为中心的一组数字,或者是一组基本上具有相同中心的数字,中间位置为1。

因此,计算中间值,然后计算是否需要和差距。然后你就完成了。

如果n是奇数,那么中间是N/n(假设整数除法),向右移动1,以考虑余数。因此,例如,如果N为10000且n为17,则中间为588,您的起始范围为588±(17-1)/ 2,即580-596。但余下的是4,所以转换4,你的回答是580-592,594-597。

如果n中间是半数的话。所以中间是(N-n/2)/n + 0.5。因此,例如,如果N为10000且n为18,则中间值为555.5,起始范围为555.5±(18-1)/ 2,即547-564。但是那个师的余数为1,所以我们得到了547-563,565的答案。