前言
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元
一、暴力解法
看到题目依据条件求和,我第一时间想到的就是暴力解法,遍历数组,寻找适合条件的数据(惭愧惭愧,自身实力拉胯,只能先解决问题再优化问题),当我付诸实际的时候,暴力解法确实很符合逻辑,写的也很快,但是问题出现了,题目要求不能出现重复的解,我使用暴力解法,截、解出来是全部解,难免有重复,尝试了一些解决办法依旧不太行,只好看了题解,发现大佬们就是大佬,利用排序和双指针的算法,逻辑通俗易懂,还完美的解决了题目。暴力解法我就不贴出来献丑了。
二、排序+双指针解法
1.排序 + 双指针
本题的难点在于如何去除重复解。
算法流程:
1、特判,对于数组长度 nn,如果数组为 null 或者数组长度小于 3,返回 []。
2、对数组进行排序。
3、遍历排序后数组:
4、若 nums[i]>0:因为已经排序好,所以后面不可能 有三个数加和等于 00,直接返回结果。
5、对于重复元素:跳过,避免出现重复解
令左指针 L=i+1,右指针 R=n-1,当 L<R时,执行循环:
6、当 nums[i]+nums[L]+nums[R]==0,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将 L,R 移到下一位置,寻找新的解
若和大于 00,说明 nums[R]nums[R] 太大,R 左移
若和小于 00,说明 nums[L]nums[L] 太小,L 右移
代码如下(示例):
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
n=len(nums)
res=[]
if(not nums or n<3):
return []
nums.sort()
res=[]
for i in range(n):
if(nums[i]>0):
return res
if(i>0 and nums[i]==nums[i-1]):
continue
L=i+1
R=n-1
while(L<R):
if(nums[i]+nums[L]+nums[R]==0):
res.append([nums[i],nums[L],nums[R]])
while(L<R and nums[L]==nums[L+1]):
L=L+1
while(L<R and nums[R]==nums[R-1]):
R=R-1
L=L+1
R=R-1
elif(nums[i]+nums[L]+nums[R]>0):
R=R-1
else:
L=L+1
return res
作者:wu_yan_zu
链接:https://leetcode-cn.com/problems/3sum/solution/pai-xu-shuang-zhi-zhen-zhu-xing-jie-shi-python3-by/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2.C++版本
大佬写了题解思路,又写了python例程,我要是还不会那也太丢人了,参考了题解评论里面一位大哥写的C++版,利用C++也是通过了这道题。(简单的加了点注释,配合思路看更佳)。
代码如下(示例):
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ans;
//数组内元素小于3个,直接返回
if(nums.size()<3)return ans;
//数组排序
sort(nums.begin(),nums.end());
//排序后,如何全是正数,那么不可能有三个数之和为零了
if(nums[0]>0)return ans;
int i = 0;
while(i < nums.size()){
if(nums[i]>0)break;
int Left = i+1;
int Right = nums.size()-1;
while(Left < Right){
//防溢出
long long x = static_cast<long long>(nums[i]);
long long y = static_cast<long long>(nums[Left]);
long long z = static_cast<long long>(nums[Right]);
if(x+y+z>0){
Right--;
}else if(x+y+z<0){
Left++;
}else{
ans.push_back({nums[i],nums[Left],nums[Right]});
//避免重复元素导致重复解
while(Left<Right&&nums[Left] == nums[Left+1]){
Left++;
}
while(Left<Right&&nums[Right] == nums[Right-1]){
Right--;
}
Left++;
Right--;
}
}
while(i<nums.size()-1&&nums[i]==nums[i+1]){
i++;
}
i++;
}
return ans;
}
};
总结
1、作为一名未来的嵌入式工程师,我用的更多的可能是C,更多的是C的基础语法。但是对于这些面向对象也只会一些基础语法,更多的函数库和多样的封装好的库函数所知甚少,使用了这些库函数才发现直接调用是真的香。
2、在学习嵌入式的工程中可能算法的用武之地不多,但是学习一些算法,却可以提高个人的四位和解决问题的方式,对于做一个项目,解决一个问题,尝试用另外的方法很重要,解决问题的方式在一代代更新,人也在不断的进步。
3、学习一些算法其实也是在理解计算机思维的方式,对于一个问题,我认为首先解决问题,再优化问题,当然对于有一定实力的人来说,边解决边优化是更好的选择。理解计算机思维才能更好的优化自己写的代码。所以学习算法也很重要也是必不可少的。
4、学习的路上,你我共勉。