几天前,我接受了面试,他们问我如何用c语言计算所有数字2或5的倍数之和,从1到10000。我这样做了:
int mult2_5()
{
int i, sum=0;
for(i = 1; i <= 10000; i++)
if(i % 2 == 0 || i % 5 == 0)
sum += i;
return sum;
}
我想知道这个实现是否更快?
答案 0 :(得分:5)
模数运算符效率低下。更快的实现将是这样的:
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)。
另一种更好的解决方案是采用数学方法。
你试图将这样的所有数字相加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);
}
答案 1 :(得分:2)
如果你的意思是“更快”,那么首先在纸上做好。
$ 2 \ sum_ {1&lt; = 2k&lt; = 10000} k + 5 \ sum_ {1&lt; = 5k&lt; = 10000} - 10 \ sum_ {1&lt; = 10k&lt; = 10000} k $
对不起,我的SO等式很弱......无论如何,这条路线会给你几乎可以在纸上处理的东西:减少几步后的5000 * 6001
int
mult2_5(void)
{
return 5000*6001;
}
Project Euler problem 1非常相似。有很多人将他们的解决方案发布到这个。
答案 2 :(得分: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 :(得分:1)
这可以用数学来完成。像2 * sum(1 to 5000) + 5 * sum(1 to 2000) - 10 * sum(1 to 1000).
一样的错误就像运动一样。
答案 4 :(得分:0)
我几乎完成了一个纯粹而简单的乘法,做一个简单的循环,以35(2 + 4 + 5 + 6 + 8 + 10之和)开始,步长为60,这就是你的结果会增加多少当你拿下一批时,例如(+ i = 35; i <5976; i = i + 60){sum = sum + i} 12 + 14 + 15 + 16 + 18 + 20等 5976来自5975,是以1000结尾的最后一行数字,即992 + 994 + 995 + 996 + 998 + 1000。 事实证明,这个循环运行了100次,第一次转弯时总和增加了35次,剩余的99次增加了60次。现在可以简化为简单乘法等。