2020/3/7
题目描述
给输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例
示例 1:
输入:target = 9
输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]
相关标签
数学
Sliding window
解题思路
算法:
数学法
我们可以在本题中找到这样一个规律:
例如 9 可以被 3 整除,商为 3 ,这意味着我们找到了一个解 [2,3,4];又例如 9 可以被 2 除,得商 4,余数 1,于是我们又找到了另一个解 [4, 5]。
从中我们可以找到一个规律,即若存在一个为奇数的除数 div,且 target 正好可以被整除,那么存在一个以除数 div 为中心的数列,其和为被除数;若存在一个为偶数的除数 div ,且 target 被除后得到的余数为 div/2+1,那么存在一个以除数为中心的数列,其和为被除数。
双指针法
我们可以通过两个指针 (left, right) 从头到尾的来遍历整个数组。
如果下标从 left 到 right 的数组元素之和小于 target,那么说明之后可能还存在元素使得(left,right)加上之后等于target,此时 left 不动,right 右移;
如果大于target,说明以 left 为起点的子数列之和无法满足等于 target 的要求。left应当右移。
若等于 target,说明找到了满足条件的子数列,保存该子数列后,left 与 right都右移一位,继续搜索解。复杂度分析:
时间复杂度:O(target)
空间复杂度:O(1)
源代码
数学法
impl Solution {
pub fn find_continuous_sequence(target: i32) -> Vec<Vec<i32>> {
let mut res = vec![];
for div in (2..target/2 + 2).rev() {
let q = target / div;
if div % 2 == 0 && target % div == div / 2 && q - div / 2 + 1 > 0 {
res.push((q - div / 2 + 1 ..= q + div / 2).collect());
}
else if div % 2 > 0 && target % div == 0 && q - div / 2 > 0 {
res.push((q - div / 2 ..= q + div / 2).collect());
}
}
res
}
}
执行用时 : 0 ms, 在所有 Rust 提交中击败了100.00%的用户
内存消耗 : 2.1 MB, 在所有 Rust 提交中击败了100.00%的用户
总结
数学法中,由于结果要求需要从小到大排序,所以需要倒序遍历。