当Rust遇上LeetCode 面试题57 - II. 和为s的连续正数序列 [简单]

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> {
        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%的用户

总结

数学法中,由于结果要求需要从小到大排序,所以需要倒序遍历。

你可能感兴趣的:(当Rust遇上LeetCode 面试题57 - II. 和为s的连续正数序列 [简单])