题目
思路
首先将数组进行从小到大的排序,然后对于小于0的数字num,设置-num是target,然后设置num后面的位置是left,数组最右边是right,将left和right向中间移动遍历,当nums[left] + nums[right] == target的时候,就将这三个数字加入到答案里面。
注意点:
- 如果num大于0的话,可以直接退出循环。(因为后面的数字肯定也大于0,没有办法做到三个数字相加为0)
- 如果当前的num和遍历到的上一个num相等,那么这次不参与计算。(遵循原则:不包含重复的三元组)
- 如果计算得到和为0,那么将当前的数字和上一个答案中的数字进行比较,如果相等,那么不加入答案。(遵循原则:不包含重复的三元组)
- 在nums[left] + nums[right] 和 target进行比较的时候,如果是 < target, 那么将left右移,如果是 > target,那么将right左移。
分析时间复杂度: 首先是排序,时间复杂度nlogn;然后对于target的访问是对数组遍历一次,然后在每次找left+right==target的过程中,都会进行一次遍历。因此最终时间复杂度是O(n^2)。
代码
var findTarget = (ans, num, target, index)=>{
let begin = index+1, end = num.length-1;
while(begin<end){
if(num[begin]+num[end]=== target){
let tmp = ans.length>0? ans[ans.length-1] : null;
if(tmp == null || -target !== tmp[0] || num[begin] !== tmp[1]){
ans.push([-target, num[begin], num[end]]);
}
begin++;
end--;
}else if(num[begin]+num[end]>target){
end--;
}else{
begin++;
}
}
}
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
// 排序,双指针,转化为两数相加=target的问题
// 时间复杂度:排序Ologn,遍历数字是n个,找到target是n,因此是n方,O(n^2)
nums.sort((a, b)=>(a - b))
let ans = new Array();
for(let i=0;i<nums.length;i++){
if(nums[i]>0){
break;
}else if(i==0 || nums[i-1] !== nums[i]){
findTarget(ans, nums, -nums[i], i);
}
}
return ans;
};