持续创作,加速成长!这是我参与「掘金日新计划 · 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();
}
};