leetcode1 Two Sum题解

        题目大概意思就是,我给你传进来一个vector容器和一个target,vector相当于一个数组,现在问target是有数组种哪两个数组成的,返回两个下标,注意函数的返回类型也是vector类型的,所以一定要注意.


        题目刚到手的时候,发现这个与各大OJ套路不太一样啊,也就是与ACM不太一样,我还傻傻的调整输出格式什么的,而且这个是完善一个类的成员函数,而不是提交一个可以运行的完整代码,觉得还是挺新奇的.


        思路分析

        最开始的时候,以为这个如果数据量不是很大的时候可以桶排序暴力破解啊,我见建立了一个10000这么大的数组,先全部初始化为-1,之后遍历整个数组,如果这个数存在则将这个数在vector中的位置存入数组中.之后在遍历一遍数组判断target-num[i]的数组是否为正数,如果为正数则push_back进vector,return即可.但是提交之后发现这尼玛vector中还要负数,导致这个就失败了,但我反过来一想我建立两个大数组不就OK了吗,一个代表正数一个代表负数,之后我就又提交了一遍然后这次小的数据都通过了,出现了一个30000多的数,我突然发现我的数组还是10000大小的,我将其改为1000000,之后sublime就报段错误(核心已转移),我猜测可能是越界了,之后我慢慢缩小到50000还是报错,想想估计是套路不对吧,to young to simple啊.


将我前几次提交的代码贴一下(RunTime Error):

#include <vector>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
using std::vector;

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        
        int RecordZ[10000];
        int RecordF[10000];
        int i,j;
        int VecLen = nums.capacity();
        int nTemp;

        vector<int> result;
        
        memset(RecordZ,-1,sizeof(RecordZ));
        memset(RecordF,-1,sizeof(RecordF));
        
        for(i=0;i<VecLen;i++)
        {
            if (nums[i]>0)
            {
                RecordZ[nums[i]] = i + 1;
            }
            else
            {
                RecordF[abs(nums[i])] = i + 1;
            }
        }


        for(i=0;i<VecLen;i++)
        {
            nTemp = target - nums[i];
            if (nTemp>0&&RecordZ[nTemp]!=-1)
            {
                result.push_back(i+1);
                result.push_back(RecordZ[nTemp]);
                return result;
            }
            else if(nTemp<0&&RecordF[abs(nTemp)]!=-1)
            {
                result.push_back(i+1);
                result.push_back(RecordF[abs(nTemp)]);
                return result;
            }
        }
    }
};

int main()
{
    Solution test;
    vector<int> Nums;
    Nums.push_back(2);
    Nums.push_back(3);
    Nums.push_back(4);
    Nums = test.twoSum(Nums, 6);
    printf("%d,%d\n",Nums[0],Nums[1]);
    return 0;
}


之后我就想大空间是不可能了,创建了一个map吧,这个可以一一对应,需要那个就查找就OK了,map的查找是二分查找,所以时间复杂度为log(n),估计得查找n-i次(i = 1,2,3,4...n),所以总体的复杂度为nlog(n),自我感觉应该没啥问题.大体思路还是差不多,只不过存储方式由数组改为了map果不其然啊AC.但是这版代码还可以继续优化,可以变得更简练,可以将两个遍历合在一起,相当于从后开始搜索,而不是从前开始搜索,比如说1,2,3,5想要组成6那么有两种取法就是(1,4)或者(4,1).如果直接从后往前查找都不用判断大小就可以直接输出了.


第一版map代码(AC)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        map<int, int> m;//存储vector中的值和下标
        map<int, int>::iterator it;//map方法返回的都是iterator类型的数据
        vector<int> result;//存储要返回的下标
        int i;//循环变量

        for(i=0; i<nums.size(); ++i)//遍历数组将所有值都插入map中
        {
            m.insert(make_pair(nums[i], i+1));
        }
        for(i=0; i<nums.size(); ++i)//循环通过target-num[i]判断是否num[i]符合原则
        {
            int another = target - nums[i];
            it = m.find(another);
            if(it != m.end()&&(it->second!=(i+1))) //因为存在如6 = 3 + 3,所以去掉位置相同的情况
            {
                if(it->second>(i+1))//将下标从大到小排序,其实也可以用sort(m.begin(),m.end())
                {
                    result.push_back(i+1);
                    result.push_back(it->second);
                    break;
                }
                else
                {
                    result.push_back(it->second);
                    result.push_back(i+1);
                    break;
                }
                
            }
        }
        return result;
    }
};

最终版代码来了(AC)


class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        map<int, int> m;//存储vector中的值和下标  
        map<int, int>::iterator it;//map方法返回的都是iterator类型的数据  
        vector<int> result;//存储要返回的下标  
        int i;//循环变量  
        for(i=0; i<nums.size(); ++i)
        {
            int another = target - nums[i];
            it = m.find(another);
            if(it == m.end())   // 没找到,加入缓冲区
            {
                m.insert(make_pair(nums[i], i+1));
            }
            else
            {
                result.push_back(it->second);
                result.push_back(i+1);
                break;
            }
        }
        return result;
    }
};


 

 

反过来想也可以将vector输入到map中,之后从小到大排好序,定义两个变量i指向队头j指向队尾,之后将Num[i]+Num[j]的值与target判断大小,如果相等则输出,如果大于则j--,否则i++.

bool cmp(pair<int,int> &p1, pair<int,int> &p2) {
    return p1.first < p2.first;
}

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<pair<int,int>> v;         
        for(int i=0; i<nums.size(); ++i)
            v.push_back(make_pair(nums[i], i+1));

        sort(v.begin(), v.end(), cmp);  

        int i = 0;//队头
        int j = v.size()-1;//队尾
        vector<int> res;
        while(i < j) {//其实和快排差不多,都是两个指针分别像左向右
            int sum = v[i].first + v[j].first;
            if(sum == target) {
                res.push_back(v[i].second);
                res.push_back(v[j].second);
                break;
            }
            else if(sum < target)
                ++i;
            else
                --j;
        }

        sort(res.begin(), res.end());

        return res;
    }
};





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值