15. 三数之和 + 双指针
题目来源
题目描述
给你一个包含 n
个整数的数组 nums
,判断 nums
中是否存在三个元素 _a,b,c ,_使得 a + b + c = 0 ?请你找出所有和为 0
且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
示例 1:
输入: nums = [-1,0,1,2,-1,-4]
输出: [[-1,-1,2],[-1,0,1]]
示例 2:
输入: nums = []
输出: []
示例 3:
输入: nums = [0]
输出: []
提示:
0 <= nums.length <= 3000
-105 <= nums[i] <= 105
相似题目
题目解析
解法一:双指针
java代码
package com.walegarrett.interview;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @Author WaleGarrett
* @Date 2021/2/21 20:21
*/
/**
* 题目描述:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?
* 请你找出所有和为 0 且不重复的三元组。
*/
public class LeetCode_15 {
public List<List<Integer>> threeSum(int[] nums) {
int len = nums.length;
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
//为防止重复,从小到大枚举a
for(int a=0; a<len; a++){
//需要和上次枚举的数不同
if(a>0 && nums[a] == nums[a-1])
continue;
//c对应从最右端开始枚举
int c = len-1;
int leave = -nums[a];
for(int b=a+1; b<len; b++){
if(b > a+1 && nums[b] == nums[b-1])
continue;
// 需要保证 b 的指针在 c 的指针的左侧
while(b<c && nums[b]+nums[c] > leave){
c--;
}
if(b == c)
break;
if(nums[b] + nums[c] == leave){
List<Integer> list = new ArrayList<>();
list.add(nums[a]);list.add(nums[b]);list.add(nums[c]);
result.add(list);
}
}
}
return result;
}
}
复杂度分析
- 时间复杂度:O(\(N^2\)),其中 N 是数组 nums 的长度。
- 空间复杂度:O(logN)。我们忽略存储答案的空间,额外的排序的空间复杂度为 O(logN)。然而我们修改了输入的数组 nums,在实际情况下不一定允许,因此也可以看成使用了一个额外的数组存储了 nums 的副本并进行排序,空间复杂度为 O(N)。
参考
解法二:双指针-nSum问题模板
代码实现
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
int n = nums.length;
Arrays.sort(nums);
return nSum(nums, 3, 0, 0);
}
private List<List<Integer>> nSum(int[] sum ,int n, int pos, int target){
int size = sum.length;
List<List<Integer>> res = new ArrayList<>();
if(n < 2 || size < n){
return res;
}else if(n == 2){
int left = pos, right = size-1;
while(left < right){
int tempsum = sum[left] + sum[right];
int leftnum = sum[left], rightnum = sum[right];
if(tempsum < target){
while(left < right && sum[left] == leftnum){
left++;
}
}else if(tempsum > target){
while(left < right && sum[right] == rightnum){
right--;
}
}else{
List<Integer> list = new ArrayList<>(){{
add(leftnum);
add(rightnum);
}};
res.add(list);
while(left < right && sum[left] == leftnum){
left++;
}
while(left < right && sum[right] == rightnum){
right--;
}
}
}
}else{
for(int i=pos; i<size; i++){
int num = sum[i];
List<List<Integer>> ans = nSum(sum, n-1, i+1, target-num);
for(List<Integer> temp : ans){
temp.add(num);
res.add(temp);
}
while(i < size - 1 && sum[i] == sum[i+1]){
i++;
}
}
}
return res;
}
}
参考
Either Excellent or Rusty