题目描述:
给定一个包含 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
看到三数之和第一反应就是两数之和升级版,(当时没接触过双指针)。如果两数之和用到两遍for循环,那么三数之和需要用到三遍for循环,实在太多循环了,程序很容易卡死,去寻求简易方法,了解到了双指针。
解决双指针问题通常需要3种方法:左右指针,快慢指针,后序指针。三数之和可以采用左右指针来解决。对左右指针的理解, 个人以高中时排座位经历为例:班主任为均衡不同学习情况的学生的座位分布,让每个学习小组的学习能力接近相似,于是他采取了按照学习成绩由高到低组成一个序列。成绩最高的和成绩最低的组成同桌,成绩次最高的和成绩次最低的组成同桌。以此类推,从成绩最高往后数,成绩逐渐降低的,从成绩最低的往前数,成绩逐渐升高的,组成同桌。左右指针可以理解为在一个序列最前和最后开始两个指针,分为向后进行向前进行,直到达到想要的结果或者两个指针相遇。
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums,target) {
//先排序,组成一个有序数组
//为达到和为0,三个数之中一定至少有1个有数小于0,一定至少有1个数大于0
var nums = nums.sort((a,b)=>{return a-b})
// 设定目标值target
var arrSum = target;
//为结果准备一个空数组
var arr = [];
var len = nums.length;
for(var i=0;i<len-1;i++){
//三个数已经在排序数组中了,如果三数之中第一个数大于等于0 ,那么和一定不可能为0
if(nums[i]>0){
break
}
//排序数组的第一个不重复数组会在剩下往后的数字中寻找能达到目标和的两外两个数,
//所以存重复数字的话跳过接着(题目要求:构成不重复的的数组)
if(nums[i] == nums[i-1]){
continue
}
//第一个数确定下来arr[i] 两个数在其之后,为了达到和为0 ,另外两个数采用左右指针
// 采用左右指针便可以根据和大于0 左指针向右移动(越向右,数字越大)
//和如果小于0 右指针向左移动
var j = i+1,
k = len-1;
//结束条件为两指针相遇
while(j < k){
let sum = nums[i]+nums[j]+nums[k];
if(sum == arrSum){
arr.push([nums[i],nums[j],nums[k]])
let arrLen = arr.length;
//此处是为了数组去重
if(arrLen>1 && (arr[arrLen-1][0] == arr[arrLen-2][0]) && (arr[arrLen-1][1] == arr[arrLen-2][1]) &&(arr[arrLen-1][2] == arr[arrLen-2][2])){
arr.pop();
}
j++;
continue;
}else if(sum < arrSum){
j++;
continue;
}else if(sum > arrSum){
k--;
continue;
}
}
}
return arr;
};复制代码