目录
1.Leetcode 1 两数之和
- 题目描述
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
- 思路分析
- 使用map做hashmap,使用额外的空间(n),一趟遍历进行判断。如果不在map,就加入,在map就计数。
- 因为需要返回下标,所以用sort+双指针不方便。
- 代码设计
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int>res;
int n=nums.size();
map<int,int>hashmap;
for(int i=0;i<n;++i)
{
if(hashmap.find(target-nums[i])!=hashmap.end()&&hashmap[target-nums[i]]!=i)//存在
{
res.push_back(i);
res.push_back(hashmap[target-nums[i]]);
break;
}
else
hashmap[nums[i]]=i;
}
return res;
}
};
2.Leetcode 15 三数之和
- 题目描述
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
- 思路分析
- 第一种思路,时间复杂度为N*2,空间复杂度为N。对于三个数,我们分成两部分,固定一个数,然后使用Two Sum的思路,去判断这个数的负数是不是有Two sum的解。Two Sum的求解办法是使用一个map,进行O(n)的遍历,边遍历边放进map中。但是需要考虑到数组中有重复元素,所以结果集合里面也有重复,所以需要判断一下,如果结果集合中已经有这个解了,就不再加入。
- 第二种思路,时间复杂度为NlogN。我们采用快速排序的库函数,得到排序后的数组。我们也是像第一种思路一样,固定一个数,然后去寻找两个数之后是该数的负数。因为现在是排序数组,所以我们可以采用双指针遍历查找,为了避免重复组合,我们需要将两个指针设置到一个范围,比如都在目标数的右侧且相互不相遇。如果不加约束,那么会出现重复的组合:比如a[i]+a[j]=target;a[j]+a[i]=target。除此之外,我们还有两个策略去避免重复:
- 对于固定的数,这个数不可以重复选取,重复的话就跳过。
- 对于两个指针的遍历的过程,遇到解之后,接着寻找其他解的时候,需要跳过之前解的重复值。
- 代码设计
//超时代码
class Solution {
public:
void twoSum(vector<int>&nums,int target,int k,vector<vector<int>>&res)
{
map<int,int>m;
for(int i=0;i<nums.size();++i)
{
if(m.find(target-nums[i])!=m.end()&&m[target-nums[i]]!=i&&i!=k&&m[target-nums[i]]!=k)
{
vector<int>pos;
pos.push_back(nums[i]);
pos.push_back(nums[m[target-nums[i]]]);
pos.push_back(nums[k]);
sort(pos.begin(),pos.end());
//在结果集合里面找答案
vector<vector<int> > ::iterator it=find(res.begin(),res.end(),pos);
if(it==res.end())//不在里面
res.push_back(pos);
}
else
m[nums[i]]=i;
}
}
vector<vector<int>> threeSum(vector<int>& nums) {
vector< vector<int> >res;
int n=nums.size();
for(int i=0;i<n;++i)
{
twoSum(nums,-nums[i],i,res);
}
return res;
}
};
//pass
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector< vector<int> >res;
//排序NlogN
sort(nums.begin(),nums.end());
int n=nums.size();
for(int i=0;i<n-2;++i)
{
if(i>0&&nums[i]==nums[i-1])//枚举元素的时候需要跳过重复元素
continue;
int target=-nums[i];
//双指针
int low=i+1;
int high=n-1;
while(low<high)
{
if(nums[low]+nums[high]<target)
++low;
else if(nums[low]+nums[high]>target)
high--;
else
{
vector<int>pos;
pos.push_back(nums[i]);
pos.push_back(nums[low]);
pos.push_back(nums[high]);
res.push_back(pos);
//找完之后 可能还有其他组合 所以跳过重复元素 接着遍历查找
++low;
while(low<high&&nums[low]==nums[low-1])
++low;
--high;
while(low<high&&nums[high]==nums[high+1])
--high;
}
}
}
return res;
}
};
3.Leetcode 16 最接近的三数之和
- 题目描述
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum-closest
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
- 思路分析
三数之和的变形问题,排序+双指针。
- 代码设计
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
int n=nums.size();
sort(nums.begin(),nums.end());
int cur=0;
int res=nums[0]+nums[1]+nums[2];
for(int i=0;i<n-2;++i)
{
int low=i+1;
int high=n-1;
while(low<high)
{
cur=nums[i]+nums[low]+nums[high];
if(abs(cur-target)<abs(res-target))
res=cur;
if(nums[low]+nums[high]+nums[i]<target)
++low;
else if(nums[low]+nums[high]+nums[i]>target)
--high;
else
return target;
}
}
return res;
}
};
4.Leetcode 18 四数之和
- 题目描述
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/4sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
- 思路分析
结合三数之和的方法,首先将前两个数进行枚举,然后使用双指针进行查找后面两个数。时间复杂度为O(n^2logn)。在枚举过程中要注意去重。需要考虑就是在每一个数考虑的时候不要重复,四个数之间可以有重复的数,比如都是输入[0,0,0,0] target=0,那么结果集合为[[0,0,0,0]].
- 代码设计
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
//先排序
sort(nums.begin(),nums.end());
int n=nums.size();
vector<vector<int>>res;
for(int i=0;i<n-3;++i)
{
if(i>0&&nums[i]==nums[i-1])
continue;
for(int j=i+1;j<n-2;++j)
{
if(j>i+1&&nums[j]==nums[j-1])//和第一个数和第二个数是可以相等的 只要第二个数不要取重复值就可以
continue;
int ans=nums[i]+nums[j];
int low=j+1;
int high=n-1;
while(low<high)
{
if(nums[low]+nums[high]+ans<target)
++low;
else if(nums[low]+nums[high]+ans>target)
--high;
else
{
vector<int>pos;
pos.push_back(nums[i]);
pos.push_back(nums[j]);
pos.push_back(nums[low]);
pos.push_back(nums[high]);
res.push_back(pos);
++low;
while(low<high&&nums[low]==nums[low-1])
++low;
--high;
while(low<high&&nums[high]==nums[high+1])
--high;
}
}
}
}
return res;
}
};
5. Leetcode 454 四数之和II
- 题目描述
给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。
为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -228 到 228 - 1 之间,最终结果不会超过 231 - 1 。
例如:
输入:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
输出:
2
解释:
两个元组如下:
1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/4sum-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
- 思路分析
使用map进行hash操作,分成两组数分别遍历,第一组数的和存储在map里(数,这种组合出现的次数)。然后使用map的查找功能判断第二组数的和是否在map里,统计次数。这道题返回的是组合数,算是比较简单。并且不考虑重复组合,只要组合的下标不一样就可以。
- 代码设计
class Solution {
public:
int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
map<int,int>Map;
int res=0;
for(int i=0;i<A.size();++i)
{
// if(i>0&&A[i]==A[i-1])
// continue;
for(int j=0;j<B.size();++j)
{
// if(j>0&&B[j-1]==B[j])
// continue;
int ans=-(A[i]+B[j]);
if(Map.find(ans)==Map.end())
Map[ans]=1;
else
Map[ans]+=1;
}
}
for(int i=0;i<C.size();++i)
{
// if(i>0&&C[i-1]==C[i])
// continue;
for(int j=0;j<D.size();++j)
{
// if(j>0&&D[j-1]==D[j])
// continue;
int ans=C[i]+D[j];
if(Map.find(ans)!=Map.end())
res+=Map[ans];
}
}
return res;
}
};