人的最大区别是算力而不是执行力:个人如果进步不大其实有时候可能不是他不够努力,而是被太多低效的目标占据了精力,需要避免低水平重复建设,做人做事应该思考怎么做才可以做的更好,而不是陷入低水平重复。
思路
-
使用暴力解法
-
思路:通过设置三层循环分别寻找数组中的三个数字a b c,使得a + b + c 等于 0,最后返回一个数组,数组的每一项为包含a,b,c的子数组。
- 缺点:需要三重循环,时间复杂度为n^3
-
-
官方解法:使用排序 + 双指针
-
思路:将数组按照从小到大排序,代码一共设置两层循环遍历,第一层循环遍历给定的输入数组,取a为-nums[i],因为我们需要找到满足 a + b + c === 0的 a,b,c三个数,当a === -nums[i]的时候,我们需要找到满足 b + c = -nums[i]的,b和c两个数,寻找b和c的过程可以并列使用两个循环,特别的是,因为a 在第一层遍历的时候已经确定,这时候b + c ===-nums[i]其实是一个定值,前面提到,给定输入的数组已经按照小到大排序过了,所以b随着遍历越来越大的时候,接下来能够满足条件的c一定是越来越小的,所以第二层遍历寻找b的时候,代表当前b值的索引j越来越越大,代表c值的索引k值越来越小,于是我们取 j = i + 1, k = n - 1,寻找b的循环从前往后,c则是从后往前,因为这样可以使得二层循环中遍历的总次数更少。举个例子,第二层遍历,a === -4, b === -3,这时候c === 7,第二层遍历寻找b的循环进行到下一步的时候,比如a === -4, b === 2, 下次遍历寻找c可以直接从c < 7 的地方开始找,因为下次遍历中的c如果要满足条件,那么一定是比 3 === 7 要更小的,所以代表c值的索引k在每次循环中,k都从上次循环结束的地方开始继续递减,代表b值的索引则是不断递增。当二层循环一轮结束,重新回到第一层循环的下个回合,这之后,再将k重置为 k = n-1 ,n 为给定输入数组的长度。
-
优点:
- 时间复杂度降低到n^2;
- 对排序后的数,做了是否相等的判断,可以避免额外的深层遍历的成本(if ((i > 0) && (nums[i] === nums[i - 1])) 等)。
-
题目
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
示例 1:
输入: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] 。
注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。
提示:
3 <= nums.length <= 3000-105 <= nums[i] <= 105
代码:官方解法
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
let n = nums.length;
nums.sort((a, b) => a - b);
let ans = [];
for (let i = 0; i < n; i++) {
// 需要和上次枚举的值不同;
if ((i > 0) && (nums[i] === nums[i - 1])) {
continue;
}
// c对应的指针在数组最右边
let k = n - 1;
let target = -nums[i]
// 枚举 b
for (let j = i + 1; j < n; j++) {
if (j > (i + 1) && nums[j] === nums[j - 1])
continue;
// 需要保证b指针在c的指针左侧
while (j < k && nums[j] + nums[k] > target) {
k -= 1
}
if (k === j) {
break;
}
if (nums[j] + nums[k] === target) {
ans.push([nums[i], nums[j], nums[k]])
}
}
}
return ans;
};