两数之和
双指针
两数之和问题显而意见是用双指针来写,要想使用双指针前提是数组提前有序。这道题的坑就在这里,数组无序,我们需要先排序,但是题目让返回的却是数字所在原数组的下标,如果已排序就乱了,因此有两种方法,一种就是我认为简单的我们在进行排序,只不过把下标和数组放在一起进行排序。
#include<bits/stdc++.h>
int vis[100100];
//这里的默认为是大于号
bool cmp(pair<int,int>a, pair<int,int> b)
{
if(a.first!=b.first)
{
return a.first<b.first;
}
else {
return a.second<b.second;
}
}
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int l=0;
int r=nums.size()-1;
vector<pair<int,int> > num;
for(int i=0;i<nums.size();i++)
{
num.push_back(make_pair(nums[i],i));
}
sort(num.begin(),num.end(),cmp);
vector<int> v;
while(l<r)
{
pair<int,int> t1=num[l];
pair<int ,int> t2=num[r];
if(t1.first+t2.first==target)
{
v.push_back(t1.second);
v.push_back(t2.second);
break;
}
else if(t1.first+t2.first>target)
{
r--;
}
else l++;
}
return v;
}
};
hash表
先遍历一遍数组,将数组中的元素和下标存放于一个无序的哈希表中,其中数组中的元素为key,下标为value。
遍历一遍数组,利用 map的 find函数查找哈希表中是否存在 (target-当前元素的值)。 注意可能出现 target = 2numbers[i]这种情况,所以if条件判断内要 && m[target-numbers[i]] != i。 最后返回符合条件两个下标即可。
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target)
{
map<int, int> m;
int n = numbers.size();
//这一步比较巧妙,如果是target=2*x的时候
//map存放的是第二次的下标,以为第一次我们会遍历到。
for(int i=0; i<n; i++)
m[numbers[i]] = i;
for(int i=0; i<n; i++)
{
if(m.find(target-numbers[i]) != m.end() && m[target-numbers[i]] != i)
{
return {i+1, m[target-numbers[i]]+1};
}
}
return {};
}
};
三数之和
这道题的坑在于要去重,最暴力的写法就是三层for循环,第一层,第二层for循环去一下重。为什么第三层不需要去重呢,因为如果第一层和第二层的不相同了,第三层的也肯定不相同。暴力写法时间复杂度太高了,因此我们想到了里面两层使用双指针的方法进行优化,时间复杂度就变成了O(n^2)级别的了。
这道题目让求得就是数字,而不是下标,排序没什么影响。
#include<bits/stdc++.h>
class Solution {
public:
vector<vector<int> > threeSum(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int> > v;
for(int i=0;i<nums.size();i++)
{
// 第一个数去重
if(i>0&&nums[i]==nums[i-1]) continue;
int l=i+1;
int r=nums.size()-1;
while(l<r)
{
// 第二个数去重
if(l>i+1&&nums[l]==nums[l-1])
{
l++;
continue;
}
if(nums[i]+nums[l]+nums[r]==0)
{
v.push_back({nums[i],nums[l],nums[r]});
l++;
r--;
}
else if(nums[i]+nums[l]+nums[r]>0)
{
r--;
}
else l++;
}
}
return v;
}
};
最接近的三数之和
这道题就是在找三数之和或等于的情况下多一步更新最接近值,其余的完全一样。
class Solution {
public:
int best=100000000;
int update(int sum,int target)
{
if(abs(best-target)<abs(sum-target)) return best;
return sum;
}
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size();i++)
{
// 第一个数去重
if(i>0&&nums[i]==nums[i-1]) continue;
int l=i+1;
int r=nums.size()-1;
while(l<r)
{
// 第二个数去重
if(l>i+1&&nums[l]==nums[l-1])
{
l++;
continue;
}
best=update(nums[i]+nums[l]+nums[r],target);
if(nums[i]+nums[l]+nums[r]==target)
{
return target;
}
else if(nums[i]+nums[l]+nums[r]>target)
{
r--;
}
else l++;
}
}
return best;
}
};