Leetcode-15. 三数之和

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

解法:暴力探索就不说了;1. 仍然使用类似two sum的存储机制,使用set做存储,时间复杂度为O(N2),空间复杂度O(N);2. 使用双指针法进行前后夹击,时间复杂度O(N2),空间复杂度O(1)

1. using hashset

  • Java
class Solution {
   
    public List<List<Integer>> threeSum(int[] nums) {
   
        Arrays.sort(nums);
        // List<List<Integer>> list = new ArrayList<>();
        HashSet<List<Integer>> res = new HashSet<>();
        for(int i=0;i<nums.length-2;i++){
   
            if(i>0 && nums[i]==nums[i-1]) continue;
            HashSet<Integer> set = new HashSet<>();
            for(int j=i+1;j<nums.length;j++){
   
                if(set.contains(nums[j])){
   
                    res.add(Arrays.asList(nums[i],nums[j],-(nums[i]+nums[j])));
                }else{
   
                    set.add(-(nums[i]+nums[j]));
                }
            }
        }
        // return list.stream().distinct().collect(Collectors.toList()); // using java8 stream
        List<List<Integer>> lst = new ArrayList<>();
        lst.addAll(res); // convert set to list
        return lst;
    }
}
  • Python
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        res = set()
        for i,v in enumerate(nums[:-2]):
            if i>0 and v==nums[i-1]:
                continue
            set1 = set()
            for j in nums[i+1:]:
                if j in set1:
                    res.add((v,j,-(v+j)))
                else:
                    set1.add(-(v+j))
        return map(list,res)

2. using double pointer

  • Java
class Solution {
   
    public List<List<Integer>> threeSum(int[] nums) {
   
        Arrays.sort(nums);
        List<List<Integer>> lst = new ArrayList<>();
        for(int i=0;i<nums.length-2;i++){
   
            if(i>0 && nums[i]==nums[i-1]) continue;
            int l=i+1, r=nums.length-1, target = -nums[i];
                while(r>l){
   
                    if(nums[l]+nums[r]==target){
   
                        lst.add(Arrays.asList(nums[i],nums[l],nums[r]));
                        while(l+1<r && nums[l+1]==nums[l]) l++;
                        while(r-1>l && nums[r-1]==nums[r]) r--;
                        l++;r--;
                    }else if (nums[l]+nums[r]<target){
   
                        l++;
                    }else{
   
                        r--;
                    }
                }
        }
        return lst;
    }
}
  • Python
class Solution:
    def threeSum(self, nums):
        res = []
        nums.sort()
        for i in range(len(nums)-2):
            if i>0 and nums[i]==nums[i-1]:
                continue
            l,r = i+1,len(nums)-1
            while l<r:
                if nums[l]+nums[r]==-nums[i]:
                    res.append([nums[l],nums[r],nums[i]])
                    while l+1<r and nums[l+1]==nums[l]:
                        l+=1
                    while r-1>l and nums[r-1]==nums[r]:
                        r-=1
                    l+=1
                    r-=1
                elif nums[l]+nums[r]>-nums[i]:
                    r -= 1
                else:
                    l+=1
        return res

Leetcode-18. 四数之和

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:

答案中不可以包含重复的四元组。

示例:

给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。

满足要求的四元组集合为:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]

解法:可以发现这种N数之和的规律就是将N数之和转换成为(N-1)数之和,最后转换到二数之和,看起来非常适合用递归来写,所以我们直接写一个通用的解法,时间复杂度O(N^(n-1))

  • Java
class Solution {
   
    int len = 0;
    public List<List<Integer>> fourSum(int[] nums, int target) {
   
        this.len = nums.length;
        Arrays.sort(nums);
        return nSum(nums,target,4,0);
    }
    public ArrayList<List<Integer>> nSum(int[] nums, int target, int n,int index){
   
        ArrayList<List<Integer>> lst = new ArrayList<>();
        if(index>=this.len){
   
            return lst;
        }
        if(n==2){
   
            int l = index, r = this.len - 1;
            while(l<r){
   
                if(nums[l]+nums[r]==target){
   
                    List<Integer> tmp = new ArrayList<>();
                    tmp.add(nums[l]);
                    tmp.add(nums[r]);
                    lst.add(tmp);
                    // lst.add(Arrays.asList(nums[l],nums[r]));
                    while(l<r && nums[l+1]==nums[l]) l++;
                    while(l<r && nums[r-1]==nums[r]) r--;
                    l++;r--;
                }else if(nums[l]+nums[r]>target){
   
                    r--;
                }else{
   
                    l++;
                }
            }
        }else{
   
            for(int i=index;i<this.len-n+1;i++){
   
                ArrayList<List<Integer>> tmp = this.nSum(nums,target-nums[i],n-1,i+1);
                if(tmp!=null){
   
                    for(List<Integer> l:tmp){
   
                        l.add(0,nums[i]);
                    }
                lst.addAll(tmp);
                while(i<this.len-1 && nums[i]==nums[i+1]) i++;
                }
            }
        }
        return lst;
    }
}
  • Python
 class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        self.len = len(nums)
        return self.nSum(nums,target,4,0)
    
    def nSum(self, nums,target,n,index):
        lst = []
        if index >= self.len-1: return
        if n==2:
            l, r = index, self.len-1
            while l<r:
                if nums[l]+nums[r]==target:
                    lst.append([nums[l],nums[r]])
                    while l<r and nums[l]==nums[l+1]: l+=1
                    while l<r and nums[r]==nums[r-1]: r-=1
                    l += 1
                    r -= 1
                elif nums[l]+nums[r]>target:
                    r -= 1
                else :
                    l += 1
        else:
            for i in range(index, self.len-n+1):
                if index<i<self.len-1 and nums[i]==nums[i-1]:continue
                tmp = self.nSum(nums,target-nums[i],n-1,i+1)
                if tmp:
                    for l in tmp:
                        l.insert(0,nums[i])
                        lst.append(l)
        return lst