剑指offer面试题57 - II:和为s的连续正数序列(golang实现)

题目描述

输入一个正整数 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

Leetcode链接:剑指offer面试题57 - II:和为s的连续正数序列

算法分析

  • 本题使用滑动窗口法(双指针)解决,因为要找的是连续的正整数序列,所以可以用两个指针分别表示正整数序列的首尾(我用的是 i 和 j )。
  • 具体实现:
    当序列和 s u m < t a r g e t sum < target sum<target时,尾指针右移一位(很好理解,如果右移头指针的话序列和反而会变小)。
    当序列和 s u m = t a r g e t sum = target sum=target时,通过一个内层循环将该序列加入res返回数组中。之后将头指针或者尾指针右移即可寻找下一个可能的序列和。
    当序列和 s u m > t a r g e t sum > target sum>target时,将头指针右移一位使序列和减小。
  • 注意,移动指针后更新序列和可以避免每次重复计算。

复杂度分析

问题规模为target的大小n

  • 时间复杂度:O( n n n),外层循环最多循环 target / 2 次,时间复杂度为O( n n n)。
    关于内层循环时间复杂度的计算:
    由高斯求和公式:
    ( i + j ) ⋅ ( j − i + 1 ) ÷ 2 = t a r g e t , 令 t = j − i + 1 ,    ⟹    ( t + 2 ⋅ i − 1 ) ⋅ t = 2 ⋅ t a r g e t , 经 放 缩    ⟹    t 2 < 2 ⋅ t a r g e t    ⟹    t < 2 ⋅ t a r g e t \begin{aligned} &(i + j) \cdot (j - i + 1) \div 2 = target, 令 t = j - i + 1, \\ \implies & (t + 2 \cdot i - 1) \cdot t = 2 \cdot target,经放缩 \\ \implies & t^2 < 2 \cdot target \\ \implies & t < \sqrt{2 \cdot target} \end{aligned} (i+j)(ji+1)÷2=targett=ji+1(t+2i1)t=2targett2<2targett<2target
    将和为target的正整数序列视为有效序列。此时求得的t为有效序列的长度。假设极限情况下,最长的有效序列的长度可以看作 2 ⋅ t a r g e t \sqrt{2 \cdot target} 2target ,且长度为2、3、···、 2 ⋅ t a r g e t \sqrt{2 \cdot target} 2target 的有效序列全部存在(由题易知确定长度的有效序列有且只有一个),可计算出内层循环里语句在程序运行期间的总执行次数为
    t a r g e t + 2 ⋅ t a r g e t target + \sqrt{2 \cdot target} target+2target
    即O( n + n n + \sqrt{n} n+n ),所以本题虽然用了双重循环,但是由于并不是每次外层循环都会执行内层循环,导致最终的时间复杂度仍然为O( n n n)
  • 空间复杂度:O( 1 1 1)

Golang代码如下

func findContinuousSequence(target int) (res [][]int) {
	sum := 3
	for i, j := 1, 2; i < j && j <= target / 2 + 1; {
		if sum == target {
			temp := make([]int, j-i+1)
			for k := i; k <= j; k++ {
				temp[k-i] = k
			}
			res = append(res, temp)
		}
		if sum >= target {
			i++
			sum -= i - 1
		} else {
			j++
			sum += j
		}
	}
	return
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值