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。
這個題目也是逆向思維的簡單應用,並不需要複雜的算法和精妙的構思,反轉一下足夠。