虽然只是一道很简单的题,但是也给我很多思考。
刚看到这道题的时候没有仔细思考,直接写了个排序和二分查找,想着对每个数字查找另一个数字会不会出现,复杂度是 O ( n l o g n + n l o g n ) 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 ( n l o g n + 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>();
}
};
但是也没有觉得快多少,可能是因为数据比较水看不出来差距吧。