三数之和
难度:
标签:
题目描述
给你一个整数数组 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
代码结果
运行时间: 1152 ms, 内存: 18 MB
/* 思路:
1. 首先将数组排序,以便使用双指针方法。
2. 使用Java Stream进行流式处理和去重。
3. 用流的distinct方法过滤掉重复的三元组。
*/
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.stream.Collectors;
public class ThreeSumStream {
public List<List<Integer>> threeSum(int[] nums) {
if (nums == null || nums.length < 3) return new ArrayList<>();
Arrays.sort(nums); // 排序
return Arrays.stream(nums).boxed().collect(Collectors.groupingBy(x -> x)).values().stream()
.flatMap(group -> {
List<List<Integer>> triplets = new ArrayList<>();
int[] arr = group.stream().mapToInt(Integer::intValue).toArray();
for (int i = 0; i < arr.length - 2; i++) {
if (i > 0 && arr[i] == arr[i - 1]) continue; // 跳过重复
int left = i + 1, right = arr.length - 1;
while (left < right) {
int sum = arr[i] + arr[left] + arr[right];
if (sum == 0) {
triplets.add(Arrays.asList(arr[i], arr[left], arr[right]));
left++;
right--;
while (left < right && arr[left] == arr[left - 1]) left++; // 跳过重复
while (left < right && arr[right] == arr[right + 1]) right--; // 跳过重复
} else if (sum < 0) {
left++;
} else {
right--;
}
}
}
return triplets.stream();
})
.distinct()
.collect(Collectors.toList());
}
}
解释
方法:
这个题解采用排序+双指针的方法解决三数之和问题。首先将整个数组排序,然后遍历数组,对于每个元素,用双指针在该元素右侧的子数组中寻找两个数,使得这三个数的和为0。在寻找的过程中,通过双指针的移动来避免重复的三元组。
时间复杂度:
O(n^2)
空间复杂度:
O(1)
代码细节讲解
🦆
在实现 `twoSum` 函数时,你是如何确保找到的两个数与当前元素的组合是独一无二的?
▷🦆
为什么在寻找两数之和时,需要跳过重复元素,这种跳过重复元素的操作会影响到算法的正确性吗?
▷🦆
双指针方法在这里是如何有效地减少搜索空间并避免不必要的计算的?
▷🦆
你提到空间复杂度为 O(1),但是在存储答案时需要额外空间,这部分空间应该如何计算?
▷🦆
排序步骤是如何帮助优化整个算法流程的,它对双指针法有什么具体的帮助?
▷🦆
在整个数组遍历过程中,为什么需要选择固定一个元素并寻找其他两个元素,而不是固定两个元素来寻找第三个元素?
▷相关问题
两数之和
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6 输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6 输出:[0,1]
提示:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
- 只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2)
的算法吗?
最接近的三数之和
给你一个长度为 n
的整数数组 nums
和 一个目标值 target
。请你从 nums
中选出三个整数,使它们的和与 target
最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。
示例 1:
输入:nums = [-1,2,1,-4], target = 1 输出:2 解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
示例 2:
输入:nums = [0,0,0], target = 1 输出:0
提示:
3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-104 <= target <= 104
四数之和
给你一个由 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