如何檢查一個數字是否是兩個或多個連續整數的和
1.概述
在本教程中,我們將探討如何確定給定數字是否可以表示為兩個或多個連續整數的總和。
我們首先要了解連續整數序列背後的數學原理以及它們的屬性如何簡化我們的解決問題的過程。然後,我們將實作兩種方法:蠻力方法和最佳化方法。
2.數學背景
為了了解這些分解在實踐中如何發揮作用,讓我們考慮幾個例子:
9 = 2 + 3 + 4 或 4 + 5
15 = 4 + 5 + 6
10 = 1 + 2 + 3 + 4
7 = 3 + 4
相較之下,我們找不到兩個或多個連續正整數總和等於 8。
讓我們先重新審視一個直接導致識別 2 的冪的標準的結果。
當有整數k ≥ 1
和n ≥ 1
,每個正整數a
都可以寫成兩個或多個連續正整數的和,並且滿足:
a = (n+1)*k + (n*(n+1))/2
該公式來自標準的“前n 個整數之和”,移至從k
開始:
n*(n+1)/2
兩邊乘以 2,我們得到:
2a = (n+1) *2k + n*(n+1) = (n+1) * (2k + n)
有了這個等式,我們現在可以證明為什麼 2 的冪不能分解,以及為什麼其他每個正整數都能分解成功。
2.1. 2 的冪不通過測試
假設a
是 2 的冪。那麼2a
也是 2 的冪,所以它的唯一正因數就是 2 的冪。但在任何因式分解中:
2a = (n+1) * (2k+n)
無論n
是偶數還是奇數,兩個因數n+1
和2k+n
總是具有相反的奇偶性,因此它們不能是 2 的冪。
此外,為了避免簡單的情況(僅使用一個加數),我們要求n ≥ 1
且k > 0
。兩個 2 的冪乘以另一個具有相反奇偶性的 2 的冪的唯一方法是強制n+1=1
(因此n=0
)或2k+n=1
(因此k=0
),這兩者都違反了我們的限制。因此, 2 的冪不能寫成兩個或多個連續正整數的和。
2.2.其他所有整數都有效
相反,任何不是 2 的冪的整數a
都至少有一個奇數除數d > 1
:
d=2m+1, a=d*q
對於某個整數q
,序列:
(a/d - m), (a/d - m + 1), ..., (a/d + m)
由d
連續整數組成,它們的和恰好為a
。即使a/d − m ≤ 0
,也可以透過刪除負項並對稱地添加正項來移動序列以保持和(或選擇不同的奇數除數),從而保證有效的表示。
因此, 除2的冪之外的所有正整數都可以表示為兩個或多個連續正整數的和。
3. 暴力破解方法
我們將從一個簡單的方法開始:嘗試所有可能的序列長度,直到找到有效的總和或用盡我們的選擇。這種方法很容易理解,並且對於n
的中等值非常有效:
@Test
void whenIsSumOfConsecutiveUsingBruteForce_thenItsTrue() {
int n = 15;
boolean isSumOfConsecutive = false;
for (int k = 2; (k * (k - 1)) / 2 < n; k++) {
int diff = n - k * (k - 1) / 2;
if (diff % k == 0 && diff / k > 0) {
isSumOfConsecutive = true;
break;
}
}
assertTrue(isSumOfConsecutive);
}
我們循環遍歷每個可能的長度k
,計算剩餘數量是否能被整除,並檢查起始數字是否保持正數。如果找到匹配項,則傳回true
;否則,所有長度都失敗後我們將傳回false
。
4. 優化方法
我們可以將檢查簡化為單一位元運算。如果正整數n
不是 2 的冪,則可以將其寫成兩個或多個連續整數的和。否則,它不能:
@Test
void whenIsSumOfConsecutiveUsingBitwise_thenReturnsTrue() {
int n = 15;
boolean result = (n > 0) && ((n & (n - 1)) != 0);
assertTrue(result);
}
當n
為正數且未通過二次方測試時,我們傳回true
。這在恆定的時間和空間內運行,即使對於非常大的n
也非常有效。
5. 結論
在本文中,我們證明了任何正整數都可以表示為兩個或多個連續正整數的和,只要它不是 2 的冪次方即可。
我們的強力方法有條不紊地測試了每個可能的序列長度,使得對於 n 的中等值來說,它變得簡單而可靠。相較之下,優化的位元檢查給出了一個O(1)
解決方案,可以立即識別非 2 的冪,這使其成為非常大輸入的理想選擇。
與往常一樣,原始碼可在 GitHub 上取得。