【问题标题】:Fastest possible algorithm to sum numbers up to N [closed]将数字求和到 N 的最快算法 [关闭]
【发布时间】:2011-02-07 03:19:42
【问题描述】:

我想要一个真正快速的算法或 C 中的代码来完成以下任务:对任何给定整数 N 求和从 1 到 N 的所有数字,而不假设 N 是正数。我做了一个从 1 到 N 的循环求和,但是太慢了。

【问题讨论】:

  • 家庭作业,嗯...?
  • 最近不是有一篇关于程序员实际上不需要了解数学的帖子(或者甚至可能是一篇关于编码恐怖的博客文章)吗?我认为这个问题完美地说明了为什么他们确实需要了解数学! (我使用“数学”的意思是大多数外行人通常的意思,而不是包含计算机科学、逻辑等的意思)
  • 谁支持了这个问题?
  • @qrdl:有人要拿选民徽章吗?
  • 我感到震惊和震惊

标签: c++ c algorithm integer sum


【解决方案1】:

如果N 是肯定的:int sum = N*(N+1)/2;

如果N 为负数:int tempN = -N; int sum = 1 + tempN*(tempN+1)/2 * (-1);

【讨论】:

  • “如果 N 为负数”最后需要一个 + 1。 1 + 0 + -1 + -2 = -2,而不是 -3。
  • 糟糕!谢谢,错过了。
  • @Dave:是的,您应该始终执行过早的优化,因为它确实会产生影响,而编译器永远不会聪明到自己解决这个问题。另请注意,它可能会更快,因为它不做同样的事情(你想要>> 1)。
  • 没有关于如何的解释?我试一试:N/2 找到 0 到 N 之间所有数字的平均值。我们从 1 开始,所以将其更改为 (N+1)/2。现在我们有了平均值,我们只需要将其乘以序列中的值数(N)(实际上是 N-1(起始值)+1(1 到 2 包含 2 个值,而不是 2-1=1 ),但 N-1+1=N)。所以N*((N+1)/2),减少=N*(N+1)/2
  • @erikkallen:(为我的微笑点赞)。另外,我相信正确的转变是为签名数据实现定义的?
【解决方案2】:
sum = N * (N + 1) / 2

【讨论】:

  • 但这只是 O(1)!
  • 您始终可以硬编码 -32,768 到 +32,767 的总和值。更少的周期:D
  • 我认为它不适用于负数。如果 N 为 -3,则此公式给出 3 但 -3+-2+-1+0+1 = -5
  • @gmatt 是正确的,这实际上是O(log N),除非你限制N 的值,在这种情况下,天真的循环也是O(1)
  • 如果我对 wikipedia 的理解是正确的,那么 Schönhage-Strassen 算法(它似乎是发现的最快的、实用的算法)将得到 O(log N log log N log log log N) 的时间复杂度@
【解决方案3】:

您正在寻找的公式是在您的问题的多个答案中发布的公式的更一般形式,这是一个具有差异因素的Arithmetic Series/Progression 1。来自Wikipedia,如下:

只要 m 总是小于 n,上述公式将处理负数。例如,要获得从 1 到 -2 的总和,请将 m 设置为 -2 并将 n 设置为 1,即从 -2 到 1 的总和。这样做会导致:

(1 - -2 + 1) * (1 + -2) / 2 = 4 * -1 / 2 = -4 / 2 = -2.

这是预期的结果。

【讨论】:

  • +1 用于给出通用公式。
【解决方案4】:

只是为了完成上述答案,这就是您证明公式的方式(正整数示例,但原理与 Void 指出的负数或任何算术套件相同)。

只需将套件写两次如下并添加数字:

  1+   2+   3+ ... n-2+ n-1+   n   = sum(1..n)     : n terms from 1 to n
+ n+ n-1+ n-2+ ...   3+   2+   1   = sum(n..1)     : the same n terms in reverse order
--------------------------------
n+1+ n+1+ n+1+ ... n+1+ n+1+ n+1   = 2 * sum(1..n) : n times n+1

n * (n+1) / 2 = sum(1..n)

【讨论】:

  • sum(n..1) 的第三项应该是 n-2。
  • +1 直观地解释它
  • @wallacoloo:谢谢。我更正了答案(还有另一个错字)。
  • @Void:谢谢,但我没有优点,这是高斯的经典证明。
  • 你知道 complet 只能用作形容词,不能用作动词,对吧?
【解决方案5】:

为了处理整数溢出,我会使用以下函数:

sum = (N%2) ? ( ((N+1)/2)*N ) : ( (N/2)*(N+1) );

【讨论】:

  • 聪明...但这仍然容易受到整数溢出的影响。你不是在“处理”它,只是在拖延它。
  • 它会尽可能地“延迟”它。
【解决方案6】:

试试这个...

其中 n 是您需要求和的最大整数。

总和为 (n*(N+1))/2

【讨论】:

    【解决方案7】:

    int sum(int n) { return (n < 0 ? n *(-n + 1) / 2 + 1 : n * ( n + 1) / 2); }

    【讨论】:

      【解决方案8】:

      您听说过序列和系列吗?您想要的“快速”代码是从 1 到 N 的算术级数之和 .. google it .. 实际上打开您的数学书..

      【讨论】:

        【解决方案9】:

        如果 |n|足够小,查找表将是最快的。

        或者使用缓存,首先搜索缓存,如果找不到记录,则使用n * (n + 1) / 2(如果n为正)计算总和,并将结果记录到缓存中。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-04-23
          • 1970-01-01
          • 2011-02-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多