上一篇已经说到了两数之和,索性将三数之和与四数之和一起都复习一下
给你一个整数数组 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
解答
rust
//双指针
pub fn three_sum(nums: Vec<i32>) -> Vec<Vec<i32>> {
let mut resultList:Vec<Vec<i32>> =Vec::new();
let mut nums2 = nums.clone();
// 先进行排序
nums2.sort();
for i in 0..nums2.len() {
// 如果最小的都大于0,那就没有集合,直接返回
if nums2[i] > 0 {
return resultList;
}
// 去重
if i > 0 && nums2[i] == nums2[i - 1] {
continue;
}
let mut left = i + 1;
let mut rigth = nums2.len() - 1;
while left < rigth {
let n = nums2[i] + nums2[left] + nums2[rigth];
if n > 0 {
rigth -= 1;
}else if n < 0 {
left += 1;
}else {
resultList.push(vec![nums2[i],nums2[left],nums2[rigth]]);
//右侧去重
while left < rigth && nums2[rigth] == nums2[rigth - 1] {
rigth -= 1;
}
//左侧去重
while left < rigth && nums2[left] == nums2[left + 1] {
left += 1;
}
rigth -= 1;
left += 1;
}
}
}
return resultList;
}
//三数之和
fn main() {
let nums = vec![-1,0,1,2,-1,-4];
let res = three_sum(nums);
println!("{:?}", res);
}

给你一个由 n
个整数组成的数组 nums
,和一个目标值 target
。请你找出并返回满足下述全部条件且不重复 的四元组 [nums[a], nums[b], nums[c], nums[d]]
(若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a
、b
、c
和d
互不相同nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
示例 1:
输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
示例 2:
输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]
提示:
1 <= nums.length <= 200
-109 <= nums[i] <= 109
-109 <= target <= 109
四数之和与三数之和一样,无非多了一层循环,具体解法如下
rust
pub fn four_sum(nums: Vec<i32>, target: i32) -> Vec<Vec<i32>> {
let mut resultList:Vec<Vec<i32>> =Vec::new();
let mut nums2 = nums.clone();
// 先进行排序
nums2.sort();
for i in 0..nums2.len() {
//剪枝
if nums2[i] > target && nums2[i] >= 0 {
break;
}
// 第一层去重
if i > 0 && nums2[i] == nums2[i - 1] {
continue;
}
for j in i+1..nums2.len() {
// 解释一下,i=nums[0], j=nums[1], left=nums[2], rigth=nums[3]
// 第二层剪枝
if nums2[i] + nums2[j] > target && nums2[i] + nums2[j] >= 0 {
break;
}
// 第二层去重
if j > i + 1 && nums2[j] == nums2[j - 1] {
continue;
}
let mut left = j + 1;
let mut rigth = nums2.len() - 1;
while left < rigth {
let n: i32 = nums2[i] + nums2[j] + nums2[left] + nums2[rigth];
if n > target {
rigth -= 1;
}else if n < target {
left += 1;
}else {
resultList.push(vec![nums2[i], nums2[j], nums2[left],nums2[rigth]]);
//右侧去重
while left < rigth && nums2[rigth] == nums2[rigth - 1] {
rigth -= 1;
}
//左侧去重
while left < rigth && nums2[left] == nums2[left + 1] {
left += 1;
}
rigth -= 1;
left += 1;
}
}
}
}
return resultList;
}
fn main() {
let nums = vec![1,0,-1,0,-2,2];
let res = four_sum(nums, 0);
println!("{:?}", res);
}

总结,两数之和与三数之和、四数之和解法不一样,主要是因为返回值,两数之和要返回下角标不能做排序,用hashmap合适,而三数之和、四数之和是要求返回结果集且不能重复,需要对数组进行排序,用双指针更适合。