个人评价:使用暴力破解法,写出不难,但是如何继续优化还是挺值得深入思考的~
题目难度:🌟 (参考 LeeCode 简单🌟 、中等🌟 🌟 、困难🌟 🌟 🌟 )
另,通常算法题会考察分析时间复杂度和空间复杂度,可参考笔者之前的文章
和为s的连续正数序列
题目描述
输入一个正整数 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
解题思路
方法一
先拆解子问题:已知 和 以及 序列长度,可否获取正整数序列?思路如下:
- 正整数等差数列,使用算术公式,首项 first,长度 len =》sum = (first+first+len-1)*len/2
- 如果已知sum和,可直接返回正整数序列,如已知 9,长度 2 =》[4,5];长度 3 =》[2,3,4]
Go 代码如下:
func getNumList(target int, len int) []int {
list := []int{}
for i := 0; i < len; i++ { //i为序列index
list = append(list, target/len-(len-1)/2+i)
}
return list
}
回到主问题,如何得知和可以匹配什么长度的序列?
暴力遍历:长度从 2 遍历到 target/len >(len-1)/2
遍历终点的条件,可理解为序列首位得 > 1
func findContinuousSequence(target int) [][]int {
result := make([][]int, 0)
for len := 2; target/len > (len-1)/2; len++ {
s := [][]int{getNumList(target, len)}
result = append(s, result...) //注意加到数列第一个,因为长度越长,首项越小
}
return result
}
分析复杂度?🙌 时间 O(n),额外空间复杂度 O(n)
那么,是否仍有优化空间?减少计算量以及减少空间
暴力穷举示例,其实可以发现,和得满足一定的条件才可被组成正整数序列,而奇数个和偶数个序列的规律又不大相同。这个类似数学找规律,得出如下附加条件:
- 奇数个正整数序列:满足和可整除长度(理解为 中位数*个数 = 总和)
- 偶数个正整数序列:满足和×2整除长度 且 和×2除长度之后得为奇数(偶数列为对称值,递归为最小两个数,和必为奇数)
于是,我们可以增加一些条件,优化算法:
func findContinuousSequence(target int) [][]int {
result := make([][]int, 0)
for len := 2; target/len > (len-1)/2; len++ {
if (len%2 == 1) && target%len == 0 { //奇数个正整数序列
s := [][]int{getNumList(target, len)}
result = append(s, result...)
}
if (len%2 == 0) && target*2%len == 0 && target*2/len%2 == 1 { //偶数个正整数序列
s := [][]int{getNumList(target, len)}
result = append(s, result...)
}
}
return result
}
https://goplay.tools/snippet/WxIJlDSfIjI Go play~
方法二
数学公式,一元二次方程法,有兴趣的自己尝试下 Coding 吧~
总结
使用暴力破解法,写出不难,但是效率低,算法是需要优化的~
程序员还是需要数学基础的,使用数学,不少算法仍有继续优化的空间 ヾ(◍°∇°◍)ノ゙