題目描述
小明很喜歡數學,有一天他在做數學作業時,要求計算出9~16的和,他馬上就寫出了正確答案是100。但是他並不滿足於此,他在想究竟有多少種連續的正數序列的和爲100(至少包括兩個數)。沒多久,他就得到另一組連續正數和爲100的序列:18,19,20,21,22。現在把問題交給你,你能不能也很快的找出所有和爲S的連續正數序列? Good Luck!
輸出描述:
輸出所有和爲S的連續正數序列。序列內按照從小至大的順序,序列間按照開始數字從小到大的順序
解題思路
- S除奇數時,如果餘數爲0時,存在這樣的序列;
- S除偶數時,如果餘數爲偶數的一半,則存在這樣的序列;
- 需要確保序列的最左端(最小數)值大於0.
鋪開來說:
1)由於我們要找的是和爲S
的連續正數序列,因此這個序列是個公差爲1的等差數列,而這個序列的中間值代表了平均值的大小。假設序列長度爲n
,那麼這個序列的中間值可以通過(S/n)
得到,知道序列的中間值和長度,也就不難求出這段序列了。
2)滿足條件的n
分兩種情況:
n
爲奇數時,序列中間的數正好是序列的平均值,所以條件爲:(n & 1) == 1 && sum % n == 0
;
n
爲偶數時,序列中間兩個數的平均值是序列的平均值,而這個平均值的小數部分爲0.5,所以條件爲:(sum % n) * 2 == n
.
3)由題可知n >= 2
,那麼n的最大值是多少呢?我們完全可以將n
從2到S
全部遍歷一次,但是大部分遍歷是不必要的。爲了讓n
儘可能大,我們讓序列從1開始,
根據等差數列的求和公式:S = (1 + n) * n / 2
,知n < sqrt(2S)
.
初版代碼:
def FindContinuousSequence(self, tsum):
div = 2
res, soleArray = [],[]
while tsum//div >= div//2:
if (div%2)==0 and (tsum%div)==(div//2):
start = tsum//div - div//2 + 1
while start <= tsum//div + div//2:
soleArray.append(start)
start += 1
res.append(soleArray)
elif (div%2)==1 and tsum%div==0 and tsum//div > div//2:
start = tsum//div - div//2
while start <= tsum//div + div//2:
soleArray.append(start)
start += 1
res.append(soleArray)
div += 1
soleArray = []
return sorted(res)
改進版:
def FindContinuousSequence(self, tsum):
div = 2
res = []
while div <= int(math.sqrt(tsum*2)):
soleArray = []
if (div%2==0 and tsum%div == div/2) or (div%2==1 and tsum%div == 0):
start = tsum//div - div//2 + 1 if div%2==0 else tsum//div - div//2
while start <= tsum//div + div//2:
soleArray.append(start)
start += 1
res.append(soleArray)
div += 1
return sorted(res)
最終版:
def FindContinuousSequence(self, tsum):
res = []
for div in range(2,int(math.sqrt(tsum*2))+1):
if (div%2==0 and tsum%div == div/2) or (div%2==1 and tsum%div == 0):
start = tsum//div - div//2 + 1 if div%2==0 else tsum//div - div//2
res.append(list(range(start, tsum//div + div//2 + 1)))
return sorted(res)