面试题57

题目地址:https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/

题目描述

输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。

序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

题目示例

示例 1:

输入:target = 9
输出:[[2,3,4],[4,5]]
示例 2:

输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]

解题思路

暴力法:分析题目可得,若要求序列长度至少大于 2 ,则枚举上界为(target-1)/2(等价于target/2向下取整)。然后,从1开始枚举每个正整数,判断以它为起点的序列和 sum 是否等于target,若sum>target,则枚举的起点不符合要求,初始化sum=0,并跳出此次循环,并将枚举的起点i自增1,进行下一轮枚举。若sum==target,则将此轮枚举结果插入到res中,最后保存到集合v中,并初始化sum=0,结束此轮枚举。

等差数列之和+双指针:利用等差数列求和公式可得,数列之和=(首项+尾项)*项数 / 2,即target=(start+end)*(end-start+1)/2。
在本题中,我们使用双指针left和right表示当前枚举到的以left为起点到right的区间,用sum表示区间[left,right]的区间之和,然后使用求和公式sum = (left+right)*(right-left+1)/2与target相比较,,根据题目要求序列长度至少为2,初始可令left=1,right=2。

  • 若sum>target,则说明以left为起点,不存在right使得sum==target,此时,枚举下一个起点,指针left右移;
  • 若sum<targe,则说明以left为起点,right为尾点的区间之和sum还不够大,也就是right还可以更大,此时,指针right右移;
  • 若sum==target,则说明找到了满足条件的解[left,right],将解的序列放入数组v中,然后枚举下一个起点,即指针left右移;

  通过对暴力法和双指针方法对比发现,双指针考虑到了如果已知 [left,right]的区间和sum等于target ,那么枚举下一个起点的时候,区间 [left+1,right]的和必然小于target ,此时,不再需要从left+1开始重复枚举,而是从right+1开始枚举

程序源码

方法1——暴力法

class Solution {
public:
    vector<vector<int>> findContinuousSequence(int target) {
        vector<vector<int>> v;
        vector<int> res;
        int sum = 0, upLimit = (target - 1) / 2;
        for(int i = 1; i <= upLimit; i++)
        {
            for(int j = i; ; j++)
            {
                sum += j;
                if(sum > target)
                {
                    sum = 0;
                    break;
                }
                else if(sum == target)
                {
                    res.clear();
                    for(int k = i; k <= j; k++)
                    {
                        res.emplace_back(k);
                    }
                    v.emplace_back(res);
                    sum = 0;
                    break;
                }
                else
                {
                    continue;
                }

            }
        }
        return v;
    }
};

方法2——双指针

class Solution {
public:
    vector<vector<int>> findContinuousSequence(int target) {
        vector<vector<int>> v;
        vector<int> res;
        int left = 1 , right = 2;
        while(left < right)
        {       
            int sum = (left + right) * (right - left + 1) / 2;
            if(sum > target)
            {
                left++;
            }
            else if(sum == target)
            {
                res.clear();
                for(int i = left; i <= right; i++)
                {
                    res.emplace_back(i);
                }
                v.emplace_back(res);
                left++;
            }
            else
            {
                right++;
            }
        }
        return v;
    }
};
----------------------------------- 心之所向,素履所往;生如逆旅,一苇以航。 ------------------------------------------
原文地址:https://www.cnblogs.com/wzw0625/p/12505962.html