1.题目
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a ,b ,c ,使得 a + b + c = 0 ?请找出所有和为 0 且 不重复 的三元组。链接: 题目.
2示例
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
3思路
简单点的做法是用3重循环,暴力求解,显然这里时间上肯定是通过不了。
那么就得采用固定一个元素,然后采用双指针的办法进行搜索。
首先判断数组的长度,如果小于3直接就返回空数组。先对数组进行排序,先选一个元素作为固定元素(该元素从i=0到i=length-1),然后使用双指针向后查找另外两个元素。这两个指针分别为左指针(指向固定元素的下一个元素,为最小元素)和右指针(指向最右边最大的元素)。如果三者的和大于0,说明右指针指向的元素较大,需要将右指针左移,如果三者的和小于0,说明左指针指向的元素较小,需要将左指针右移。接下来就是需要处理重复的三元组了,重复的情况有两种:
- 作为固定元素的数字重复了,数组排序后,可能有重复的数字排在一起了,这个时候刚判断为一个固定元素,下一个固定元素又是同样的数值,那么就好出现重复的三元组。
- 在同一个固定元素的情况下,如果已经找到了一组符合条件的三元组了,这个时候左右指针还得继续移动看看还有没有符合条件的三原组,这个时候如果指针移动的下一个元素的值和上一个值相同,这会又找到一组符合条件的三元组,但是是重复的,需要跳过。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int length=nums.size();
if(length<=2)
return {};
vector<vector<int>> result;//存放结果
sort(nums.begin(),nums.end());//排序
for(int i=0;i<length;i++)
{
int left=i+1,right=length-1;
int fix_index=i;
if(nums[fix_index]>0) return result;//如果第一个数都大于0了,那么这个数组里就没有符合的三元组
if(fix_index>0&&nums[fix_index]==nums[fix_index-1]) continue;//去重判断,如果下一个固定的数和前面固定的数相同,那么该三元组和上一组的相同,就可以不用判断了
while(left<right)
{
if(nums[fix_index]+nums[left]+nums[right]>0)
{
right--;
}
else if(nums[fix_index]+nums[left]+nums[right]<0)
{
left++;
}
else
{//当三个元素的和为0时符合条件,加入结果中,此时需要注意的是还要继续移动左右指针继续判断
result.push_back(vector<int>{nums[fix_index],nums[left],nums[right]});
left++;//继续移动左右指针容易忽略
right--;
while(left<right&&nums[left]==nums[left-1]) left++;//在继续移动左右指针时,如果遇到同样数字的元素则跳过,避免出现重复的三元组
while(left<right&&nums[right]==nums[right+1]) right--;
}
}
}
return result;
}
};