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

     题目:输入一个递增排序的数组和一个数字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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值