Two Sum-n方优化与C++map的使用
LeetCode第一题,刚拿到题目时虽然明知道n方的遍历算法会超时,但还是不信邪的提交了一次,然而编程不存在运气,TLE不可避免。但是之后的思维方式比较直接,我并没有立刻想到O(n)的方法,想了一种先对数组进行排序,利用目标数和待选择的数的关系来减小搜索范围:
1.不存在负数:那么比目标数大的数不必搜索
2.存在负数:搜索负数和比目标大的数,或者搜索正数比目标小的数;这种情况还存在全为负数,只能按照最差的n方方式搜索。
按照这个优化思路,虽然算法严格意义上来说是n方复杂度的,但是实际性能并不一定这么差,以下是AC代码:
/** * Note: The returned array must be malloced, assume caller calls free(). */ typedef struct newtype { int num;int index; }Data; int cmp ( const void *a , const void *b ) { Data *c = (Data *)a;Data *d = (Data *)b; if(c->num != d->num) return c->num - d->num; else return d->index - c->index; } int* twoSum(int* nums, int numsSize, int target) { int *res,i,j,fuflag=numsSize,bigflag=numsSize; int tempgflag=0; int tempres; Data *data=(Data *)malloc(sizeof(Data)*numsSize); for(i=0;i<numsSize;i++) { data[i].index=i; data[i].num=nums[i]; } res=(int *)malloc(sizeof(int)*2); qsort(data,numsSize,sizeof(Data),cmp); for(i=0;i<numsSize;i++) { if(data[i].num<0) fuflag=i; if(data[i].num<=target) bigflag=i; } //1.无负数,只需到比这个数小的位置 if(fuflag==numsSize) { for (i = 0; i <=bigflag; i++) for (j = i+1; j <=bigflag; j++) if (data[i].num + data[j].num == target) { if (data[i].index > data[j].index) { res[0] = data[j].index + 1; res[1] = data[i].index + 1; } else { res[1] = data[j].index + 1; res[0] = data[i].index + 1; } break; } } else//2.有负数,所有数都比这个数大 { for (i = 0; i <= fuflag; i++) for (j = bigflag + 1; j < numsSize; j++) if (data[i].num + data[j].num == target) { tempgflag=1; if (data[i].index > data[j].index) { res[0] = data[j].index + 1; res[1] = data[i].index + 1; } else { res[1] = data[j].index + 1; res[0] = data[i].index + 1; } break; } if(tempgflag==0) { for (i = fuflag + 1; i <= bigflag; i++) for (j = i + 1; j <= bigflag; j++) if (data[i].num + data[j].num == target) { tempgflag=1; if (data[i].index > data[j].index) { res[0] = data[j].index + 1; res[1] = data[i].index + 1; } else { res[1] = data[j].index + 1; res[0] = data[i].index + 1; } break; } } if (tempgflag == 0) { for (i = 0; i <= numsSize; i++) for (j = i + 1; j <= numsSize; j++) if (data[i].num + data[j].num == target) { if (data[i].index > data[j].index) { res[0] = data[j].index + 1; res[1] = data[i].index + 1; } else { res[1] = data[j].index + 1; res[0] = data[i].index + 1; } break; } } } return res; }
然而在提交之后看了solution才想到另外两种方法,由于确定是两个数字,所以用目标数减去当前某个数字,然后再在候选数里查找这个数!
可以用二分查找,也可以用hash表。
接下来就是使用C++ STL map来实现这个hash过程。
map的使用主要包括声明,赋值,查找,使用迭代器。
声明:
map<int, int> datamap;
赋值:
map遵循<key ,value >的原则,key是不可以重复的!
for(i=0;i<n;i++) datamap[nums[i]]=i;
查找:
map<int,int>::iterator it; it=datamap.find(target-nums[i]);
使用迭代器:
map的迭代器和vector并不相同,需要使用->来获取元素不能直接使用*
if(it!=datamap.end()&&it->second!=i)
使用map的AC代码:
1 class Solution { 2 public: 3 vector<int> twoSum(vector<int>& nums, int target) { 4 map<int, int> datamap; 5 vector<int> res; 6 int i; 7 int n=nums.size(); 8 for(i=0;i<n;i++) 9 datamap[nums[i]]=i; 10 map<int,int>::iterator it; 11 for(i=0;i<n;i++) 12 { 13 it=datamap.find(target-nums[i]); 14 if(it!=datamap.end()&&it->second!=i) 15 { 16 if(i>it->second){ 17 res.push_back(it->second + 1); 18 res.push_back(i + 1); 19 20 } 21 else 22 { 23 res.push_back(i + 1); 24 res.push_back(it->second + 1); 25 26 } 27 break; 28 } 29 } 30 return res; 31 32 } 33 };
本想再试一下hashmap,但是由于并不是标准C++库,所以需要以下头文件和命名空间:
#include <ext/hash_map> using namespace __gnu_cxx;
才可以在linux上的Eclispe里编译,但是提交发现leetcode的评测环境并不支持以上库,也就没有再试,但是看到网上很多推荐使用unordered_map:
#include <tr1/unordered_map>
使用方法和map,hashmap类似。
PS:
这个题目的数据并不是排好序的!
以下是几组容易wa的测试数据:[-1,-2,-3,-4,-5] -8 ,[0,3,4,0] 0,[-3,4,3,90] 0。
这个题目也是逆向思维的简单应用,并不需要复杂的算法和精妙的构思,反转一下足够。
posted on 2015-06-26 12:32 holyprince 阅读(340) 评论(0) 编辑 收藏 举报