【问题标题】:algorithm c sum multiples of 2 and 5算法 c 将 2 和 5 的倍数相加
【发布时间】:2012-11-20 00:25:03
【问题描述】:

几天前我有一个工作面试,他们问我如何使用 c 语言计算从 1 到 10000 的所有 2 或 5 的倍数的总和。我这样做了:

int mult2_5()
{
     int i, sum=0;
     for(i = 1; i <= 10000; i++)
        if(i % 2 == 0 || i % 5 == 0)
          sum += i;
     return sum;  
}

我想知道它是否比这个更快的实现?

【问题讨论】:

  • 运行需要多长时间?您的性能要求是什么?
  • 2 + 4 + ... + 10000 == 2 * ( 1 + 2 + ... + 5000 ) == 2 * 5001 * 2500,所以迭代计算是浪费时间.余数是 5 + 15 + ... + 9995 == 5 * ( 1 + 3 + ... + 1999 ) == 5 * ( 2000 * 1000 ) / 2 ... 那你为什么要迭代呢?
  • 我希望在您的采访中您返回 sum 并将其初始化为零。
  • 在条目中我把算法做对了,只是把错误复制到这里。我做这个算法是因为我数学很烂-.-

标签: c performance algorithm


【解决方案1】:

模数运算符效率低下。一个更快的实现是这样的:

int multiply2_5(int max)
{
  int i, x2 = 0,x5 = 0,x10 = 0;

  for(i = 2; i < max; i+=2)    x2 += i;    // Store all multiples of 2   O(max/2)
  for(i = 5; i < max; i+=5)    x5 += i;    //  Store all multiples of 3  O(max/5)
  for(i = 10; i < max; i+=10)  x10 += i;   //   Store all multiples 10;  O(max/10)

  return x2+x5-x10;
}

在这个解决方案中,我必须取出 10 的倍数,因为 2 和 5 的倍数是 10,所以在第二个循环中,它将添加第一个循环中已经添加的 10 的倍数;三个循环组合有 O(8/10 max)。

另一个更好的解决方案是采用数学方法。

您正在尝试对所有数字求和,例如 2 + 4 + 6 + 8 ... 10000 和 5 + 10 + 15 +20 + ... 10000 这与 2 * (1 + 2 + 3 + 4 + ... + 5000) 和 5 * ( 1 + 2 + 3 + 4 + ... + 2000),'n' 自然数之和为 (n * (n + 1)) (source) 所以你可以在一个固定的时间内计算,如下:

int multiply2_5(int max)
{
    // x = 2 + 4 + 6 + ... = 2 * (1 + 2 + 3 +...)
    // y = 5 + 10 + 15 + ... = 5 * (1 + 2 + 3 +...)
    // The sun of n natural numbers is sn = (n (n + 1)) / 2
   int x2 = max/ 2;                      // 2 * ( 1 +2 + 3 … max/2)
   int x5 = max /5;                      // 5 * ( 1 +2 + 3 … max/5)
   int x10 = max/ 10;                  
   int sn2 = 0.5 * (x2 * (x2+1));        // (n * (n + 1)) / 2
   int sn5 = 0.5 * (x5 * (x5+1)); 
   int sn10 = 0.5 * (x10 * (x10+1));
   return (2*sn2) + (5 *sn5) - (10*sn10);
}

【讨论】:

    【解决方案2】:

    如前面的回答中所述,显式循环遍历相关倍数比在每个循环中测试余数要好。但不必计算 10 的倍数并减去。只需从 5 点开始,然后按 10 点逐步跳过它们。

    int multiply2_5b(int max)
    {
      int i, x2 = 0,x5 = 0;
    
      for (i = 2; i < max; i += 2)    x2 += i;    // Sum all multiples of 2   
      for (i = 5; i < max; i += 10)   x5 += i;    // Sum all odd multiples of 5
    
      return x2 + x5;
    }
    

    【讨论】:

      【解决方案3】:

      如果这就是您所说的“更快”的意思,请先在纸上解决。

      $2\sum_{1

      对不起,我的 SO equation-fu 很弱……无论如何,这条路线会给你一些你几乎可以在纸上处理的东西:减少几个步骤后的 5000*6001

      int
      mult2_5(void)
      {
          return 5000*6001;
      }
      

      Project Euler problem 1 非常相似。有很多人已经发布了他们的解决方案。

      【讨论】:

      • 没有。不过,我错了 5000*6001 需要纸张。通过检查很容易乘以。
      • 500*601 远远不够大。仅能被 2 整除的总和就是 2500 万左右。
      【解决方案4】:

      这可以通过数学来完成。像2 * sum(1 to 5000) + 5 * sum(1 to 2000) - 10 * sum(1 to 1000). 这样的错误作为练习留下。

      【讨论】:

        【解决方案5】:

        通过执行一个以 35(2 + 4 + 5 + 6 + 8 + 10 的总和)开始的简单循环,我几乎得到了一个纯粹而简单的乘法,步长为 60,因为这就是你的结果会增加多少当你拿下一批时,例如12 + 14 + 15 + 16 + 18 + 20 等 for(int i=35;i

        【讨论】:

          猜你喜欢
          • 2019-12-15
          • 2012-01-14
          • 1970-01-01
          • 1970-01-01
          • 2023-03-24
          • 2011-05-12
          • 2016-11-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多