题目
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
思考
-
解法一:中位数
对于符合条件的连续正数序列,他们的中位数就是平均数:
如果中位数是整数,说明序列长度是奇数;
如果中位数小数部分是0.5, 说明序列长度是偶数。
因此,对于给定的序列长度,可以根据中位数来拼接得到整个正数序列。
当然序列长度是有范围的:
2 < = l e n g t h < = t s u m 2<= length <= tsum 2<=length<=tsum -
解法二:滑动窗口+求和公式
转自剑指Offer(四十一):和为S的连续正数序列 | Jack Cui
如果已知序列的首元素和尾元素,那么根据求和公式可以得出:
s u m = ( h e a d + t a i l ) ∗ ( t a i l − h e a d + 1 ) / 2 sum = (head+tail)*(tail-head+1)/2 sum=(head+tail)∗(tail−head+1)/2
计算得到的sum与tsum比较,会有如下三种情况:
- sum == tsum, 记录序列[head:tail+1],接着考虑下一个序列,head+=1;
- sum < tsum, 将序列范围范围扩大,tail+=1;
- sum > tsum, 说明前后两次[tail:head+1]的sum刚好落在tsum两侧,以head为起始的正数序列不满足要求,接着考虑下一个序列。head+=1。
代码
- 解法一
# -*- coding:utf-8 -*-
class Solution:
def FindContinuousSequence(self,tsum):
res = []
i = tsum
while i >= 2:
if i%2 == 0 and divmod(tsum,i)[1] != 0 and divmod(float(tsum)/i*10,5)[1] == 0 and tsum/i-i/2+1 >= 1 : #偶数个,那么中位数的小数部分必为0.5
res.append([x for x in range(int(tsum/i)-i/2+1,int(tsum/i)+i/2+1)])
if i%2 != 0 and tsum%i == 0 and tsum/i-(i-1)/2 >= 1: #奇数个,那么中位数必为整数
res.append([x for x in range(tsum/i-(i-1)/2,tsum/i+(i+1)/2)])
i -= 1
return res
- 解法二
# -*- coding:utf-8 -*-
class Solution:
def FindContinuousSequence(self, tsum):
# write code here
low, high = 1,2
res = []
while low < high:
sum = (low+high)*(high-low+1)/2
if sum == tsum:
res.append([x for x in range(low, high+1)])
low += 1
elif sum < tsum:
high += 1
else:
low += 1
return res