LeetCode 面试题 57 - Ⅱ. 和为s的连续正数序列【Easy】【Python】【滑窗】【数学】
问题
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9 输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15 输出:[[1,2,3,4,5],[4,5,6],[7,8]]
限制:
1 <= target <= 10^5
思路
解法一
滑动窗口
i 指针表示窗口左边界,j 指针表示窗口右边界。 当 sum < target 时,j 指针右移。 当 sum > target 时,i 指针右移。 当 sum = target 时,窗口内的数组加入 res,i 指针右移。 注意窗口的 range 是左闭右开 [ )。
时间复杂度: O(n)
Python3代码
class Solution: def findContinuousSequence(self, target: int) -> List[List[int]]: # solution one: sliding window i, j = 1, 1 sum = 0 res = [] while i <= target // 2: if sum < target: # j + 1 sum += j j += 1 elif sum > target: # i + 1 sum -= i i += 1 else: arr = list(range(i, j)) res.append(arr) # i + 1 sum -= i i += 1 return res
解法二
求根公式
可以看出是等差数列,于是想到求和公式:
设 x 为首项,y 为末项,则 y-x+1 为项数。设和为 target:
将上式展开:
根据求根公式:
去掉负数根,就能得到下式:
Python3代码
class Solution: def findContinuousSequence(self, target: int) -> List[List[int]]: # solution two: formula res = [] for y in range(1, target // 2 + 2): # range:[ ) x = (1/4 + y**2 + y - 2*target) ** (1/2) + 0.5 if type(x) != complex and x - int(x) == 0: # x can't be complex and x must be int res.append(list(range(int(x), y + 1))) return res
解法三
间隔法
根据解法二的求根公式,将 i = y - x 代入,得到:
进一步化简,得到:
最终得到:
于是,得到两个条件: 1. i(i+1)/2 要小于 target 2. 分子必须可以整除分母
Python3代码
class Solution: def findContinuousSequence(self, target: int) -> List[List[int]]: # solution three i, res = 1, [] while i*(i+1)/2 < target: if not (target - i*(i+1)/2) % (i+1): x = int((target - i*(i+1)/2) // (i+1)) res.append(list(range(x, x+i+1))) i += 1 # reverse return res[::-1]