持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情
每日刷题 2022.10.27
- leetcode原题链接:leetcode.cn/problems/3s…
- 难度:中等
题目
- 给你一个整数数组
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
-10^5 <= nums[i] <= 10^5
解题思路
- 三数之和,因为题目中要求了:不能包含重复的三元组,因此需要有序。
- 双指针+排序
总结提炼
- 从数组中取
n
个数,和为m
。(数组的长度一定是大于n
的) - 这个时候就不太能使用固定一个数,找剩下的数的方法了;因为现在是找
n
个数。 - 遇到类似的
n
个,就可以枚举,如果选上当前的元素 或者 不选当前的元素的情况,对最终的结果的影响是什么?由此可以想到:使用dfs
来解决问题。
dfs
解法
dfs
的深度就是:数组的长度len
;sum
表示:选中的数值之和,用于判断最终的和是否等于m
;select
表示:当前被选中的值的个数(优化:当选中的值的个数 >n
,那么就可以直接淘汰掉这种情况,不符合);tar
表示:找到的符合要求的数组组成的集合。dfs
的每一层都需要先判断:当前是否已经将数组中的每一个值的情况都考虑到了,如果都考虑到了,即:idx === len
,那么就判断当前是否符合n和m
的要求,将符合要求的放入到最终的答案结果中。- 紧接着就需要判断当前层的值,选
or
不选,不选的时候,直接dfs
下一层;选的时候需要将当前选中的值select
放入到tar
中,接着dfs
下一层,返回回来的时候,需要将其还原回原来的样子(也就是将select
从tar
中取出来)。
AC
代码
// 选出n个数,和为m, 找到符合的就返回
let arr = nums, m = 0, n = 3, len = arr.length, ans = [], flag = false;
// 参数表示:select选择的个数, sum当前被选中的总和, idx下标, tar符合要求的数组成的集合
dfs(0, 0, 0, []);
return ans;
function dfs(select, sum, idx, tar) {
if(idx === len) {
// 此时需要比较是否符合n个,且和为m
if(select === n && sum === m) {
// 记录下来
ans.push([...tar])
}
return;
}
// 如果当前选中的数,已经超过了n, 就可以直接返回
if(select > n) return;
// 不选
dfs(select, sum, idx + 1, tar, flag);
if(flag) return;
// 选
let cur = arr[idx];
// 将当前的值插入到符合要求的数组中
tar.push(cur);
dfs(select + 1, sum + cur, idx + 1, tar, flag);
if(flag) return;
// 回溯,还原回原本的样子
tar.pop();
}
};