![](/img/trans.png)
[英]Why does this not work when trying to find the sum of all multiples of 3 and 5 in 1000?
[英]Function to get the sum of all numbers multiples of 3, 5, 7 until 1000
computeMultiplesSum (n)方法应返回严格小于n的3或5或7的所有正倍数的总和。
例如,对于n = 11 ,我们得到3、5、6、7、9、10作为倍数,这些倍数的总和是40 。
实现computeMultiplesSum (n) 。
约束: 0 = <n <1000
public class Solution_Multiple {
public static int computeMultiplesSum(int n) {
int sum=0;
for(int i=0;i<n;i++)
if(i%3 == 0|| i%5 == 0||i%7 == 0)
sum+=i;
return sum;
}
public static void main(String[] args) {
System.out.println(Solution_Multiple.computeMultiplesSum(11));
}
}
但是我通过运行上面的代码得到的结果是: 420而不是40 。
如何修复其他代码以获得40的结果?
由于您的代码很好,因此可以按预期工作。 然而,模算子是低效的。 更快的实现将是这样的:
static int computeMultiplesSum2(int n){
int x3 = 0,x5 = 0, x7 = 0;
int x15 = 0, x21 = 0, x35 = 0;
int x105 = 0;
for(int i = 3; i < n; i+=3) x3 += i;
for(int i = 5; i < n; i+=5) x5 += i;
for(int i = 7; i < n; i+=7) x7 += i;
for(int i = 15; i < n; i+=15) x15 += i;
for(int i = 21; i < n; i+=21) x21 += i;
for(int i = 35; i < n; i+=35) x35 += i;
for(int i = 105; i < n; i+=105) x105 += i;
return x3 + x5 + x7 - x15 - x21 - x35 + x105;
}
在这个解决方案中,我必须取出 15、21 和 35 的倍数,因为:
由于 105 可以被 3、5、7 整除,所以会被加 3 次,因为它可以被 15、21、35 整除,所以会被删除 3 次,所以我们需要在最后加上,否则我们会删除太多。
另一个更好的解决方案(时间复杂度为O(1)
)是采用数学方法。
您正在尝试对所有数字求和,例如 3 + 6 + 9 + 12... 1000 和 5 + 10 + 15 +20 +... 10000 这与 3 * (1 + 2 + 3 + 4 + ... + 333) 和 5 * ( 1 + 2 + 3 + 4 +... + 200),'n' 自然数之和是 (n * (n + 1)) (source ) 所以你可以计算恒定时间如下:
static int computeMultiplesSum3(int n){
int x3 = (n - 1) / 3; // 3 * ( 1 +2 + 3 … (n-1)/3)
int x5 = (n - 1) / 5; // 5 * ( 1 +2 + 3 … (n-1)/5)
int x7 = (n - 1) / 7;
int x15 = (n - 1) / 15;
int x21 = (n - 1) / 21;
int x35 = (n - 1) / 35;
int x105 = (n - 1) / 105;
int sn3 = (x3 * (x3 + 1)) / 2;
int sn5 = (x5 * (x5 + 1)) / 2;
int sn7 = (x7 * (x7 + 1)) / 2;
int sn15 = (x15 * (x15 + 1))/ 2;
int sn21 = (x21 * (x21 + 1))/ 2;
int sn35 = (x35 * (x35 + 1))/ 2;
int sn105 = (x105 * (x105 + 1))/2;
return (3*sn3) + (5 *sn5) + (7 * sn7) - (15*sn15) - (21 *sn21) - (35 * sn35)
+ (105 * sn105);
}
代码完全按照您的要求执行,如果您没有将 sum 初始化为 3 并提供 '11' 作为实际参数,您将得到您想要的。
假设 sum = 0 在开始求和之前,则 3、5 和 7 的所有倍数 < 40 (0 + 3 + 5 + 6 + 7 + 9 + 10 + 12 + 14 + 15 + 18 + 20 + 21 + 24 + 25 + 27 + 28 + 30 + 33 + 35 + 36 + 39) = 417
在 if 正文中添加 print 语句以通过循环获取 i 的 state:
System.out.print(i+" + ");
这是一种使用Set<Integer>
检测重复项的方法,但我仍然认为必须有一个更数学的解决方案,可以针对更大的n
值(例如1,000,000
)扩展到任意数量的素因子。 我不喜欢嵌套循环或使用集合。
public static int computeMultipleSums(int n) {
Set<Integer> dups = new HashSet<>();
int sum = 0;
int[] primeFactors = {3,5,7};
for (int p : primeFactors) {
for (int i = p; i < n; i += p) {
sum += dups.add(i) ? i : 0;
}
}
return sum;
}
更好的、可扩展的方法是使用BitSet
。 通过设置因子的所有倍数,可以捕获重复项,因为它们只是再次设置并且不会将任何内容添加到总和中。
(n+(f-1))/f
确保当f
整除和不整除n
时终止是一致的long
用于求和以适应较大的n
值public static long computeMultipleSumsBit(int n) {
BitSet b= new BitSet();
int[] factors = {3,5,7};
for (int f : factors) {
for (int i = 1; i < (n+(f-1))/f; i++) {
b.set(f*i); // set the ith position of f
}
}
return b.stream().mapToLong(a->a).sum();
}
不是那么优雅,但要解决 O(1) 复杂性,但还要考虑到不要多次添加公倍数,这里有一个替代方案:
public static int computeMultiplesSum(int n) {
n--;
int multiplesCount = 0;
int sum = 0;
if (n >= 3) {
multiplesCount = n / 3;
sum += (multiplesCount * (3 + multiplesCount * 3)) / 2;
}
if (n >= 5) {
multiplesCount = n / 5;
sum += (multiplesCount * (5 + multiplesCount * 5)) / 2;
}
if (n >= 7) {
multiplesCount = n / 7;
sum += (multiplesCount * (7 + multiplesCount * 7)) / 2;
}
if (n >= 15) { // 3 * 5
multiplesCount = n / 15;
sum -= (multiplesCount * (15 + multiplesCount * 15)) / 2;
}
if (n >= 21) { // 3 * 7
multiplesCount = n / 21;
sum -= (multiplesCount * (21 + multiplesCount * 21)) / 2;
}
if (n >= 35) { // 5 * 7
multiplesCount = n / 35;
sum -= (multiplesCount * (35 + multiplesCount * 35)) / 2;
}
if (n >= 105) { // 3 * 5 * 7
multiplesCount = n / 105;
sum += (multiplesCount * (105 + multiplesCount * 105)) / 2;
}
return sum;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.