面试题41:和为s的两个数字VS和为s的连续正数序列

来源:互联网 发布:spycall在淘宝怎么买 编辑:程序博客网 时间:2024/05/02 02:29

     题目:输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。输出描述,对应每个测试案例,输出两个数,小的先输出。

代码如下:

class Solution {public:    vector<int> FindNumbersWithSum(vector<int> array,int sum) {        map<int,int> map1;        map<int,int> resultmap;        map<int,int>::iterator iter;        vector<int> vect;        int i;        for(i=0;i<array.size();i++)        {            if(map1.count(array[i]))                resultmap[array[i]]=sum-array[i];            else                map1[sum-array[i]]=array[i];        }        int minval=INT_MAX,val,num1=0,num2=0;        for(iter=resultmap.begin();iter!=resultmap.end();++iter)        {            val=(iter->first)*(iter->second);            if(val<minval)            {                num1=iter->first<iter->second?iter->first:iter->second;                num2=iter->first>iter->second?iter->first:iter->second;                  minval=val;                 }         }        if(minval!=INT_MAX)        {            vect.push_back(num1);            vect.push_back(num2);        }        return vect;    }};

分析一下,采用的是一个map去记录遍历过的数字,key为sum-data[i],value为该值,以便在后面出现sum-data[i],可以记录下来,这样一对就是和为sum的值对。存在resultmap中。然后寻找乘积最小的对数。时间复杂度的话我觉得是遍历O(n*lgn),count应该是lgn。

但好像并没有用到题设中的数组是排序的这一条件。于是看了书上的想法。果然精简。

class Solution {public:    vector<int> FindNumbersWithSum(vector<int> array,int sum) {        int i=0,j=array.size()-1;        map<int,int> resultmap;        map<int,int>::iterator iter;        vector<int> vect;        while(i<j)        {            if(array[i]+array[j]==sum)            {                resultmap[array[i]]=array[j];                i++;                j--;            }            else if(array[i]+array[j]<sum)                i++;            else                j--;        }        int minval=INT_MAX,val,num1=0,num2=0;        for(iter=resultmap.begin();iter!=resultmap.end();++iter)        {            val=(iter->first)*(iter->second);            if(val<minval)            {                num1=iter->first;                num2=iter->second;                minval=val;            }                   }        if(minval!=INT_MAX)        {            vect.push_back(num1);            vect.push_back(num2);        }        return vect;    }};
思路也很清楚,因为是排序数组,如果array[i]+array[j]>sum;说明大了,j减一个,如果小了,i加一个。

该题还有一种扩展:

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

输出描述:输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序。
同时考虑small和big分别为最小,最大值。如果从small到big的最大值小于sum,则增加big,否则增加small(相当于丢弃原来的small,值减小),代码如下:
class Solution {public:    vector<vector<int> > FindContinuousSequence(int sum) {        vector<vector<int> > result;        int small=1;        int big=2;        int j;        int middle=(1+sum)/2;        int cursum=small+big;        while(small<middle)        {            if(cursum==sum)            {                InsertToVect(result,small,big);                cursum-=small;                small++;                           }            else if(cursum<sum)            {                big++;                cursum+=big;            }            else            {                cursum-=small;                small++;            }        }        return result;    }    void InsertToVect(vector<vector<int> > & v,int small,int big)    {        vector<int> vect;        int i;        for(i=small;i<=big;i++)            vect.push_back(i);        v.push_back(vect);    }};


0 0