剑指Offer--041-和为S的连续正数序列

链接


牛客OJ:和为S的连续正数序列

九度OJ:http://ac.jobdu.com/problem.php?pid=1354

GitHub代码: 041-和为S的连续正数序列

CSDN题解:剑指Offer–041-和为S的连续正数序列

牛客OJ 九度OJ CSDN题解 GitHub代码
041-和为S的连续正数序列 1354-和为S的连续正数序列 剑指Offer–041-和为S的连续正数序列 041-和为S的连续正数序列

题意



题目描述

小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!

输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序

输入描述

5

100

输出描述

2 3

9 10 11 12 13 14 15 16

18 19 20 21 22

题目一:和为sum的两个数



我们先考虑个简单的

参见

LeetCode题解–1. Two Sum

牛客OJ 九度OJ CSDN题解 GitHub代码
041-和为S的两个数字 1352-和为S的连续正数序列 剑指Offer–041-和为S的连续正数序列 041-和为S的两个数字

题目描述


输入一个递增排序的数组和一个数字s,在数组中查找两个数,得它们的和正好是s。如果有多对数字的和等于s,输出乘积最小的即可。

举例说明

例如输入数组{1 、2 、4、7 、11 、15 }和数字15.

由于4+ 11 = 15 ,因此输出4 和11 。

解题思路  


考虑韦达定理

设一元二次方程x2+qx+q=0的两个根x1,x2,那么

x1+x2=?p

x1?x2=q

即以x1,x2的一元二次方程是x2?(x1+x2)x+(x1?x2)=0

而该方程有根的判别式子为:q2?4q>=0

数列满足递增,设两个头尾两个指针i和j,

* 若ai + aj == sum,就是答案(相差越远乘积越小)

  • 若ai + aj > sum,aj肯定不是答案之一(前面已得出 i 前面的数已是不可能),j -= 1
  • 若ai + aj < sum,ai肯定不是答案之一(前面已得出 j 后面的数已是不可能),i += 1

那么怎么保证输出的两个数最小呢?

比如

1 2 3 4 5 6

相隔距离越远。乘积也越大

1?6<2?5<3?4

因此我们从两端分别向中间走,先找到的那一对和一定最小

代码


class Solution
{
public:
    vector<int> FindNumbersWithSum(vector<int> array,int sum)
    {
        vector<int> res;

        if (array.size( ) < 2)
        {
            return res;
        }

        int start = 0, end = array.size( ) - 1;
        long curSum;

        while (start < end)
        {
            curSum = array[start] + array[end];

            if (curSum == sum)
            {
                ///  左右夹逼
                ///  同时能保证乘积最小的
                /// 和为sum的最大的两个数最接近sqrt(sum)
                res.push_back(array[start]);
                res.push_back(array[end]);

                break;
            }
            else if (curSum < sum)
            {
                start++;
            }
            else
            {
                end--;
            }
        }

        return res;
    }
};

和为S的连续正数序列



解题思路

考虑用两个数start和end分别表示序列的最小值和最大值。首先把start初始化为1, end初始化为2。如果从start到end的序列的和大于s,我们可以从序列中去掉较小的值,也就是增大start的值。如果从start到end的序列的和小于s,我们可以增大big,让这个序列包含更多的数字。因为这个序列至少要有两个数字,我们一直增加start到(1+s)/2 为止。

以求和为9 的所有连续序列为例,我们先把start初始化为1, end初始化为2。此时介于start和end之间的序列是{1,2},序列的和为3,小于9,所以我们下一步要让序列包含更多的数字。我们把end增加1 变成3,此时序列为{ I, 2,坷。由于序列的和是6,仍然小于9,我们接下来再增加end变成4,介于start和end之间的序列也随之变成{ l, 2, 3, 4}。由于列的和10 大于9,我们要删去去序列中的一些数字, 于是我们增加start变成2,此时得到的序列是{2, 3, 4}, 序列的和E好是9。我们找到了第一个和为9 的连续序列,把它打印出来。接下来我们再增加big,重复前面的过程,可以找到第二个和为9 的连续序列{4,5}。

#include <iostream>
#include <vector>

using namespace std;

#define __tmain main

#ifdef __tmain

#define debug cout

#else

#define debug 0 && cout

#endif // __tmain

class Solution
{
public:
    vector< vector<int> > FindContinuousSequence(int sum)
    {
        vector< vector<int> > res;
        vector<int> currRes;

        if(sum < 3)
        {
            return res;
        }

        int begin = 1, end = 2, mid = (sum + 1) / 2;
        int currSum = begin + end;
        while(begin < mid && end < sum)
        {
            ///  和正好是sum的话, 就存储下来
            if(currSum == sum)
            {
                currRes.clear( );
                for(int i = begin; i <= end; i++)
                {
                    debug <<i <<" ";
                    currRes.push_back(i);
                }
                debug <<endl;
                res.push_back(currRes);

                ///  存储完以后, 进一步往下走
                end++;
                currSum += end;
            }
            else if(currSum > sum)  /// 如果和太大了, 缩短起始位置
            {
                currSum -= begin;
                begin++;
            }
            else if(currSum < sum)  ///  如果和太小了, 那么增加结束位置
            {
                end++;
                currSum += end;
            }
        }

        return res;
    }
};

int __tmain( )
{
    Solution solu;

    vector< vector<int> > res = solu.FindContinuousSequence(100);

    debug <<"Total Count = "<<res.size( ) <<endl;
    for(unsigned int i = 0; i < res.size( ); i++)
    {
        debug <<"Count = " <<i <<", Size = "<<res[i].size( ) <<endl;
        for(unsigned int j = 0; j < res[i].size( ); j++)
        {
            cout <<res[i][j] <<" ";
        }
        cout <<endl;
    }

    return 0;
}
时间: 2024-10-15 07:38:09

剑指Offer--041-和为S的连续正数序列的相关文章

【剑指offer】和为定值的连续正数序列

转载请注明出处:http://blog.csdn.net/ns_code/article/details/27823291 题目描写叙述: 小明非常喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他立即就写出了正确答案是100.可是他并不满足于此,他在想到底有多少种连续的正数序列的和为100(至少包含两个数).没多久,他就得到还有一组连续正数和为100的序列:18,19,20,21,22.如今把问题交给你,你能不能也非常快的找出全部和为S的连续正数序列? Good Luck! 输入:

剑指offer系列46---和为s的连续正数序列

[题目]输出所有和为S的连续正数序列.序列为:1,2,3,4,5,6,7,8................ * 序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序 1 package com.exe9.offer; 2 3 /** 4 * [题目]输出所有和为S的连续正数序列.序列为:1,2,3,4,5,6,7,8................ 5 * 序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序 6 * @author WGS 7 * 8 */ 9 import ja

剑指offer:和为S的连续正数序列

http://wiki.jikexueyuan.com/project/for-offer/question-forty-one.html 例如输入 15,由于 1+2+3+4+5=4+5+6=7+8=15,所以结果打出 3 个连续序列 1-5.4-6 和 7-8 考虑用两个数 small 和 big 分别表示序列的最小值和最大值. 首先把 small 初始化为 1,big 初始化为 2. 如果从 small 到 big 的序列的和大于 s,我们可以从序列中去掉较小的值,也就是增大 small

【剑指offer】和为S的连续正数序列

题目:小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100.但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数).没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22.现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck! 输出描述:输出所有和为S的连续正数序列.序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序 思路:和为sum,那么sum/2+sum/2+1

【剑指offer】 和为s的连续正数序列,C++实现

原创博文,转载请注明出处! # 题目 # 思路 设置两个辅助变量small和big,small表示序列的最小值,big表示序列的最大值.如果sum(small ~ big) > s,则增大small的值.如果sum(small ~ big)  <  s ,则增大big的值.因为序列要求至少两个数字,所以small增加到(s+1)/2为止. # 代码 #include <iostream> #include <vector> using namespace std; cl

剑指offer-面试题57_2-和为s的连续正数序列-穷举法

/* 题目: 输入一个整数s,输出所有和为s的连续整数序列. */ /* 思路: 穷举法. */ #include<iostream> #include<cstring> #include<vector> #include<algorithm> #include<map> using namespace std; vector<vector<int> > FindContinuousSequence(int sum) {

剑指OFFER之最大子向量和(连续子数组的最大和)(九度OJ1372)

题目描述: HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天JOBDU测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决.但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止).你会不会被他忽悠住? 输入: 输入有多组数据,每组测试数据包括两行. 第一行为一个整数n(0<=n<=100000),当

【剑指offer】栈的压入弹出序列

转载请注明出处:http://blog.csdn.net/ns_code/article/details/26077863 剑指offer上的第22题,九度OJ上AC. 题目描述: 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列. 输入: 每个测试案例包括3行: 第一行为1个整数n(

剑指offer之寻找丑数,待字闺中之序列生成分析

题目来源:剑指offer之寻找丑数 与 待字闺中之序列生成分析 两个题目其实是同一个问题,所有放在一起,算是总结一下,题目如下: 给定一个表达式2^i*2^j,其中i,j为非负整数.请找到一种方法,生成如下序列: 2^0 * 5^0 = 1 2^1 * 5^0 = 2 2^2 * 5^0 = 4 2^0 * 5^1 = 5 2^3 * 5^0 = 8 2^1 * 5^1 = 10 2^4 * 5^0 = 16 2^2 * 5^1 = 20 2^0 * 5^2 = 25 ... ... ... 阅

剑指offer——二叉搜索树的后序遍历序列

题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出true,否则输出false.假设输入的数组的任意两个数字都不相同. 思路:首先二叉搜索树是指左子树全部小于根节点,右子树全部大于根节点的树.故: 对于一棵树:首先找到右子树的第一个节点,然后判断右子树中是否有小于根节点的节点,若有,则输出false. 1 public class Solution { 2 public boolean VerifySquenceOfBST(int [] sequence) { 3