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