虽然只是一道很简单的题,但是也给我很多思考。
刚看到这道题的时候没有仔细思考,直接写了个排序和二分查找,想着对每个数字查找另一个数字会不会出现,复杂度是O(nlogn+nlogn)O(nlogn+nlogn)O(nlogn+nlogn),主要训练了一下自己手写快速排序和二分查找。
class Solution {void swap(vector<int>& a,vector<int>& b,int i,int j){int t=a[i]; a[i]=a[j]; a[j]=t;t=b[i]; b[i]=b[j]; b[j]=t;}void getPovit(vector<int>& a, vector<int>& b,int l,int r){//三者取中得到枢纽int mid = (l+r) >> 1;if(a[l] < a[mid]) swap(a, b, l, mid);if(a[r-1] < a[mid]) swap(a, b, r-1, mid);if(a[l] > a[r-1]) swap(a, b, l, r-1);}void quickSort(vector<int>& a,vector<int>& b, int l,int r){if(r-l < 2) return;int mid = (l+r) >> 1;getPovit(a, b, l, r);int povit = a[l];int i=l-1; int j=r;while(i<j){do ++i; while(a[i] < povit);do --j; while(a[j] > povit);if(i < j) swap(a, b, i, j);}quickSort(a, b, l, j+1);quickSort(a, b, j+1, r);}int bSearch(vector<int>& a, int l,int r,int x,int now){if(r<=l) return -1;int mid = (l+r) >> 1;if( a[mid] == x && mid != now) return mid;if(a[mid] < x) return bSearch(a, mid+1, r, x, now);else return bSearch(a, l, mid, x, now);}
public:vector<int> twoSum(vector<int>& nums, int target) {vector<int> b;int n = nums.size();for(int i=0; i<n; ++i){b.push_back(i);}quickSort(nums, b, 0, n);// sort(nums.begin(), nums.end());vector<int> ret;for(int i=0; i<n; ++i){int tmp = target - nums[i];int j = bSearch(nums, 0, n, tmp, i);if(-1 != j){ret.push_back(b[i]); ret.push_back(b[j]);break;}}return ret;}
};
上面的做法很傻,稍微聪明一点的做法是排序以后从两边开始查找。这样的复杂度是O(nlogn+n)O(nlogn+n)O(nlogn+n)的。因为我们求的是两个数字的和,所以对于一个排好序的数组来讲,如果一个数字增大,另一个数字一定减小。因此我们用两个指针,一个指向数组的头部,一个指向数组的尾部,如果出现所求的和就直接返回答案,如果两个指针和比目标小就将前一个指针后移,如果比目标大就把后一个指针前移。这种直觉很容易证明是正确的。
class Solution {void swap(vector<int>& a,vector<int>& b,int i,int j){int t=a[i]; a[i]=a[j]; a[j]=t;t=b[i]; b[i]=b[j]; b[j]=t;}void getPovit(vector<int>& a, vector<int>& b,int l,int r){//三者取中得到枢纽int mid = (l+r) >> 1;if(a[l] < a[mid]) swap(a, b, l, mid);if(a[r-1] < a[mid]) swap(a, b, r-1, mid);if(a[l] > a[r-1]) swap(a, b, l, r-1);}void quickSort(vector<int>& a,vector<int>& b, int l,int r){if(r-l < 2) return;int mid = (l+r) >> 1;getPovit(a, b, l, r);int povit = a[l];int i=l-1; int j=r;while(i<j){do ++i; while(a[i] < povit);do --j; while(a[j] > povit);if(i < j) swap(a, b, i, j);}quickSort(a, b, l, j+1);quickSort(a, b, j+1, r);}int bSearch(vector<int>& a, int l,int r,int x,int now){if(r<=l) return -1;int mid = (l+r) >> 1;if( a[mid] == x && mid != now) return mid;if(a[mid] < x) return bSearch(a, mid+1, r, x, now);else return bSearch(a, l, mid, x, now);}
public:vector<int> twoSum(vector<int>& nums, int target) {vector<int> b;int n = nums.size();for(int i=0; i<n; ++i){b.push_back(i);}quickSort(nums, b, 0, n);// sort(nums.begin(), nums.end());int i = 0, j = n-1;while(i < j){if(nums[i] + nums[j] == target)return vector<int>{b[i], b[j]};if(nums[i] + nums[j] < target)++i;else --j; }return vector<int>();}
};
官方给出的题解是通过使用HashMap解决的,发现这样的效率很好,然而我之前没有接触过HashMap,通过一番学习,用HashMap解决了一下。
class Solution {
public:vector<int> twoSum(vector<int>& nums, int target) {unordered_map<int, int> hashMap;unordered_map<int, int>::const_iterator it;int n = nums.size();hashMap[nums[0]] = 0;for(int i=1; i<n; ++i){it = hashMap.find(target - nums[i]);if(it != hashMap.end()){return vector<int>{it->second, i};}hashMap[nums[i]] = i;}return vector<int>();}
};
但是也没有觉得快多少,可能是因为数据比较水看不出来差距吧。