和为S的连续正数序列

和为S的连续正数序列

http://www.nowcoder.com/questionTerminal/c451a3fd84b64cb19485dad758a55ebe

描述

这是一篇针对初学者的题解。共用三种方法解决。
知识点:数学,前缀和,滑动窗口
难度:一星


题解

题目抽象:给定一个1到sum的序列,求所有和为sum的连续序列。

方法一:暴力方法

求和为sum的连续子序列,可用暴力方法,
算法步骤:

  1. 用指针i枚举目标序列的左边界
  2. 用指针j枚举目标序列的右边界
  3. 用指针k枚举区间[i, j],来计算区间和,看是否等于目标sum
    代码如下:
    class Solution {
    public:
     vector<vector<int> > FindContinuousSequence(int sum) {
         vector<vector<int>> ret;
         // 左边界
         for (int i=1; i<=sum/2; ++i) { 
             // 右边界
             for (int j=i+1; j<sum; ++j) {
                 int tmp = 0;
                 // 求区间和
                 for (int k = i; k<=j; ++k) {
                     tmp += k;
                 }
                 if (sum == tmp) {
                     vector<int> ans;
                     for (int k=i; k<=j; ++k) ans.push_back(k);
                     ret.push_back(ans);
                 }
                 else if (tmp > sum) {
                     break;
                 }
             }
         }
         return ret;
     }
    };

时间复杂度:O(N^3)
空间复杂度:O(1)

方法二:前缀和

对于求一个区间和,一贯的优化技巧是使用前缀和。比如:
![图片说明](https://uploadfiles.nowcoder.com/images/20200504/284295_1588585351879_1C6E232248AEB7DAE15E190F657B3FF1 "图片标题")
sum[i]表示前i个数的和。比如sum[1] = 1,表示前一个数的和为1sum[2] = 3, 表示前2个数的和为3.现在我们要求区间[2,4]表示求第2,3,4个数的和,就等于sum[4] - sum[1] = 9
代码中我们用一个变量来模拟这个前缀和。
代码如下:

class Solution {
public:
    vector<vector<int> > FindContinuousSequence(int sum) {
        vector<vector<int>> ret;
        int tmp = 0;
        for (int i=1; i<=sum/2; ++i) {
            for (int j=i; j<sum; ++j) {
                tmp += j;
                if (sum == tmp) {
                    vector<int> ans;
                    for (int k=i; k<=j; ++k) ans.push_back(k);
                    ret.push_back(ans);
                }
                else if (tmp > sum) {
                    // 提前剪枝
                    tmp = 0;
                    break;
                }
            }
        }
        return ret;
    }
};

时间复杂度:O(N^2)
空间复杂度:O(1)

方法三:滑动窗口

知识补充:

  1. 什么是滑动窗口?
    顾名思义,首先是一个窗口,既然是一个窗口,就需要用窗口的左边界i和右边界j来唯一表示一个窗口,其次,滑动代表,窗口始终从左往右移动,这也表明左边界i和右边界j始终会往后移动,而不会往左移动。
    这里我用左闭右开区间来表示一个窗口。比如
    ![图片说明](https://uploadfiles.nowcoder.com/images/20200504/284295_1588586066412_7E35C7D253FD76C798B44ABB19E885BF "图片标题")

  2. 滑动窗口的操作

  • 扩大窗口,j += 1
  • 缩小窗口,i += 1
    算法步骤:
  1. 初始化,i=1,j=1, 表示窗口大小为0
  2. 如果窗口中值的和小于目标值sum, 表示需要扩大窗口,j += 1
  3. 否则,如果狂口值和大于目标值sum,表示需要缩小窗口,i += 1
  4. 否则,等于目标值,存结果,缩小窗口,继续进行步骤2,3,4

这里需要注意2个问题:

  1. 什么时候窗口终止呢,这里窗口左边界走到sum的一半即可终止,因为题目要求至少包含2个数
  2. 什么时候需要扩大窗口和缩小窗口?解释可看上述算法步骤。

代码如下:

class Solution {
public:
    vector<vector<int> > FindContinuousSequence(int sum) {
        vector<vector<int>> ret;
        int l = 1, r = 1;
        int tmp = 0;
        while (l <= sum / 2) {
            if (tmp < sum) {
                tmp += r;
                ++r;
            }
            else if (tmp > sum) {
                tmp -= l;
                ++l;
            }
            else {
                vector<int> ans;
                for (int k=l; k<r; ++k) 
                    ans.push_back(k);
                ret.push_back(ans);
                tmp -= l;
                ++l;
            }
        }
        return ret;
    }
};

时间复杂度:O(N)
空间复杂度:O(1)

全部评论

相关推荐

虽然大家都在劝退读研,说读研以后也是打工,不如本科直接去打工,但随着现在研究生越来越多,很多企业招聘要求就会变成研究生起招,本科投递简历就会被卡,横向比较时也会因为"本科学历比不上研究生学历"被筛掉,而且你没发现劝退读研的基本都是读完研的人吗?而且进体制、国企等,研究生也比本科生升的快,他们拿着研究生文凭劝你一个本科生,可别当真了
炬火初现:肯定是说本科能有好工作或者满意的可以不读研啊,现在本科能找到好工作的那个不优秀,大学四年赛高中,而且还要和学校斗智斗勇,这种时候自然有的选,要是只是觉得一辈子混口饭吃,大概率也考不上研,或者考上又浑浑噩噩三年,也难说。 而且考研所谓的优势说实话是你用差不多四年的时间成本(考一年,读三年)换过来的,而且还未必读完有今年的就业市场,当然不能随便决定读。 再还要看专业,一些稀奇古怪的专业说实话根本没有办法创造出什么价值,也没钱赚(如果有爱好,可以适当降低报酬标准)。现在非92的研究生说实话也没啥太多所谓优势,难说。 所以任何时候都要具体情况具体分析,不能一概而论。 一点点小看法。欢迎大家友善讨论。
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务