zoukankan      html  css  js  c++  java
  • 面试题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;
        }
    };
    ----------------------------------- 心之所向,素履所往;生如逆旅,一苇以航。 ------------------------------------------
  • 相关阅读:
    ffmpeg给视频添加文本
    装饰器的补充以及迭代器
    闭包函数与装饰器
    函数的嵌套,名称空间,以及作用域
    函数一
    文件处理二
    字符编码及文本一
    基本数据类型及内置方法(二)
    基本数据类型的内置方法
    流程控制之if,while,for
  • 原文地址:https://www.cnblogs.com/wzw0625/p/12505962.html
Copyright © 2011-2022 走看看