![](/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.