劍指offer:和爲S的連續正數序列(Python)

題目描述

小明很喜歡數學,有一天他在做數學作業時,要求計算出9~16的和,他馬上就寫出了正確答案是100。但是他並不滿足於此,他在想究竟有多少種連續的正數序列的和爲100(至少包括兩個數)。沒多久,他就得到另一組連續正數和爲100的序列:18,19,20,21,22。現在把問題交給你,你能不能也很快的找出所有和爲S的連續正數序列? Good Luck!

輸出描述:

輸出所有和爲S的連續正數序列。序列內按照從小至大的順序,序列間按照開始數字從小到大的順序

解題思路

  1. S除奇數時,如果餘數爲0時,存在這樣的序列;
  2. S除偶數時,如果餘數爲偶數的一半,則存在這樣的序列;
  3. 需要確保序列的最左端(最小數)值大於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)
發佈了85 篇原創文章 · 獲贊 103 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章