#前言
这个暑假在家里闲着也是闲着,准备在LeetCode上每天打卡一道算法题目,学学新的知识,也方便提升一下自己。 今天做的是第15题。 ##题目详情
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。
请你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
##示例
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0
。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0
。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0
。
不同的三元组是 [-1,0,1]
和 [-1,-1,2]
。
注意,输出的顺序和三元组的顺序并不重要。
##解题思路
1.首先我想到的是直接暴力求解,但是当给定的数组到达一定的规模的时候,效率无疑会低很多,我认为暴力求解永远都是存在于最后一个解题思路的方法,因此首先排除。
2.那么就得从给定数组本身来进行求解,题目给定的数组是无序的,对于相加求和的题目来说,十分不方便,那么便可直接对给定数组进行重新排序,使用sort
函数即可。
3.排完序之后,就要按顺序查出给定数组的其中三个元素之和为0的情况。这里使用了双指针
的方法。
###双指针
双指针方法,是算法题目中较为常见的一种解决方法。其核心思想是在数组中设置两个指针,分别指向数组的头和尾,这样可以同时判定两个元素是否满足题目所要求的条件。在遍历时,设置的终止条件为头指针小于尾指针,每次遍历,依据条件选择让头指针向后移或者尾指针向前移动。 但是,本题所要求的是给定数组中三个元素的和,那么思路就很清晰了:**使用一个单独的指针`k`指向第一个元素,设置双指针法的两个指针分别为`i`、`j`,分别指向`k`后的“头”和“尾”。**意思就是,三元素之和中的固定元素是指针`k`指向的元素,剩下两个元素使用双指针法来遍历。每次双指针法遍历完后,将指针`k`向后移动,重复上述遍历。
##实现细节
1.首先是使用指针k
对数组进行遍历时,要确定一个终止条件为:如果nums[k]>0
那么直接终止判断,返回,因为数组已经有序,指针k
所指向的元素为三个元素中最小的元素,如果它都大于0
,那么比不可能出现三元素之和为0
的情况了。
2.最重要的一点是去除重复数组,题目所要求的为输出的三元数组,不能包含元素相同的数组,但是给定数组的时候,里面的很多元素是可以重复的,当我们在进行遍历的时候,就会出现相同的三元组,那么就要去除重复的三元组。 ###去重
1.首先是在大循环(即用指针k
遍历给定数组时),如果指针k
向后移动指向的元素与原来的元素数值相同,那么直接continue
这次循环,因为得到的三元数组一定是和上一轮得到的三元组相同的结果。
2.其次,是在双指针遍历时进行去重,样例为-2,0,0,0,2,2,2
时,k
指针指向-2
,i
指针指向0
,j
指针指向2
。在进行双指针遍历时,i
指针向后移动一次或者j
指针向前移动一次,都可以组成三元组,但是三元组与上一轮得到的三元组元素完全相同,每次移动i
指针或者j
指针之后都要加上一个while
循环判断:如果nums[i]==nums[i-1]
,那么再令i++
。对于指针j
同理。
#代码实现
class Solution { public:
vector<vector<int>> threeSum(vector<int>& nums) {
int len=nums.size();//给定数组的长度
vector<vector<int>> a;//要求返回的数组
int k=0;//作为标准的指针
if(len<3){
return a;
}
sort(nums.begin(),nums.end());//对给定数组进行从小到大排序
for(int k=0;k<len;k++){
if(nums[k]>0){
return a;
}
int i=k+1;//头指针
int j=len-1;//尾指针
if(k>0&&nums[k]==nums[k-1]){//标准指针指向的元素与上一个元素相同则去掉,排除重复
continue;
}
while(i<j){//双指针法,左指针一定要小于右指针
if(nums[i]+nums[j]+nums[k]==0){
a.push_back({nums[k],nums[i],nums[j]});//若三者相加为0,则加入此三元组
}
if(nums[i]+nums[j]+nums[k]<0){//若三者相加小于0,那么就让头指针后移
i++;
continue;
}
if(nums[i]+nums[j]+nums[k]>0){//若三者相加大于0,则让尾指针前移
j--;
continue;
}
i++;
while(nums[i]==nums[i-1]&&i<j){
i++;
}
j--;
while(nums[j]==nums[j+1]&&i<j){
j--;
}
}
}
return a; }
};