题目大概意思就是,我给你传进来一个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; } };
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; } };