[leetcode数组系列]2三数之和
文章首发于公众号[我是程序员小贱]
前言
秋招的结束,面试了大大小小的公司,最大的问题在于算法上。所以打算坚持在leetcode打卡,看看到底能不能行,如果你想见证,那我来开车,你坐稳,一起走向更好的远方。
在学习今天内容之前,先学习上一篇的两数之和会更好哟
leetcode两数之和求解
一 题目
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
1 leetcode链接
示例
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
2 思路1---暴力解法
在思考两数之和解决方法的时候,我们使用了两层循环把所有的结果给求出来,相信读者很快就想到三数之和我就用三个循环,很棒,思路是一样,只是之前的a+b=0,现在的b=c+d了。好了代码呈上。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
if(nums.size()<3) return{};
vector<vector<int>> res;//结果
set<vector<int>> ret;//用来去重
for(int i=0;i<nums.size()-2;i++)
{
for(int j=i+1;j<nums.size()-1;j++)
{
for(int k=j+1;k<nums.size();k++)
{
if(nums[i]+nums[k]+nums[j]==0)
{
vector<int> tp;
int a=(nums[i]<nums[j]?nums[i]:nums[j])<nums[k]?(nums[i]<nums[j]?nums[i]:nums[j]):nums[k];//放最小的元素
int b=(nums[i]>nums[j]?nums[i]:nums[j])>nums[k]?(nums[i]>nums[j]?nums[i]:nums[j]):nums[k];//放最大的元素
int c=0-a-b;
tp.push_back(a);
tp.push_back(c);
tp.push_back(b);
ret.insert(tp);
}
}
}
}
for(auto it:ret)
{
res.push_back(it);
}
return res;
}
};
3 思路2---排序加双指针
-
第一步将整个数组排序,如下图。
-
从左侧开始,选定第一个数为定值比如下面的-4,然后左右指针分别指向对应位置如下图,是不是很像快排。
-
定义的左右和定值相加
- 如果等于0,记录下三个值
- 如果小于0,左指针右移动
- 如果大于0,右指针左移
-
然后定值右移,重复这个步骤
下面先看看整体的代码,随后图解整个代码流程以及如何处理重复的情况
c++版本
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int target;
vector<vector<int>> ans;
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
if ((target = nums[i]) > 0) break;
int left = i + 1, right = nums.size() - 1;
//取出三个数 所以不用left=right
while (left < right) {
if (nums[left] + nums[right] + target < 0) ++left;
else if (nums[left] + nums[right] + target > 0) --right;
else {
ans.push_back({target, nums[left], nums[right]});
++left, --right;
//去重
//测试数据[-2,0,0,2,2]
while (left < right && nums[left] == nums[left - 1]) ++left;
while (left < right && nums[right] == nums[right + 1]) --right;
}
}
}
return ans;
}
};
一次循环的图解
如果有重复数,怎么去重的呢。如果测试数据为[-2,0,0,2,2]。
我想起在参考招聘要求的时候有句话是熟悉c/c++,java之一,同时了解python等脚本更好,所以在此放上python的方法。
python版本
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
n = len(nums)#获取列表长度
res = []#存放结果
for i in range(n):
if i > 0 and nums[i] == nums[i-1]:
continue
num1 = nums[i]#取得定值
if num1 > 0:
break
#定义双指针初始状态
j = i + 1
k = n - 1
while j < k:
total = num1 + nums[j] + nums[k]
if total == 0:
res.append((num1, nums[j], nums[k]))
j += 1
while nums[j] == nums[j-1] and j < k:
j += 1
k -= 1
while nums[k] == nums[k+1] and j < k:
k -= 1
elif total > 0:
k -= 1
while nums[k] == nums[k+1] and j < k:
k -= 1
else:
j += 1
while nums[j] == nums[j-1] and j < k:
j += 1
return res
4 总结
文中使用了两种方式来解决这个问题,第一种为复杂度较高的暴力解答,第二种使用了类似快排思想的双指针法,后面还会有更多关于双指针的用法,敬请期待。至此,想想有学会点什么了?
5 结尾
希望读者和咱一起一步一个脚印去把基础知识打牢固。如果读者发现有什么错误或者不太好的地方,欢迎私我,我会及时修改。如果觉得不错或者方便手机上查看可以在下面公众号温故复习哟!