18. 4Sum

Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note:

The solution set must not contain duplicate quadruplets.

Example:

Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.

A solution set is:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]

Solution

(1) Java

Do as a n sum solution. For 4sum, the time complexity is O(n^3). For ksum, the time complexity is O(N^(K-1)), how to get it?

suppose T(n, k) denotes the time complexity required to compute a Ksum problem for an sorted array of size n. the base cases are

T(n, 1) = n
T(n, 2) = n

now for every other k we would have to loop once through the array and check if the k-1 sum is possible from the other elements so

T(n, 3) = n*T(n, 2)
T(n, 4) = n*T(n, 3)
....
T(n, k) = n*T(n, k-1)

so for k>2 the time complexity would be

O(n^(k-1))

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> rst = new ArrayList<List<Integer>>();
        if (nums == null || nums.length <= 3) {
            return rst;
        }
        Arrays.sort(nums);
        nsum(4, 0, 0, new ArrayList<Integer>(), nums, target, rst);
        return rst;
    }

    private void nsum(int n, int startIdx, int partialSum, List<Integer> partialList, int[] nums, int target,  List<List<Integer>> rst)  {
        if (n == 2) {
            int left = startIdx;
            int right = nums.length-1;
            while (left < right) {
                int sum = nums[left]+nums[right]+partialSum;
                if (sum == target) {
                    List<Integer> list = new ArrayList(partialList);
                    list.add(nums[left]);
                    list.add(nums[right]);
                    rst.add(list);
                    while (left < right && nums[left] == nums[left+1]) {
                        left++;
                    }
                    while (left < right && nums[right] == nums[right-1]) {
                        right--;
                    }
                    left++;
                    right--;
                } else if (sum < target) {
                    left++;
                } else {
                    right--;
                }
            }
        } else {
            for (int i = startIdx; i <= nums.length-n; i++) {
                if (i != startIdx && nums[i] == nums[i-1]) {
                    continue;
                }
                partialList.add(nums[i]);
                nsum(n-1, i+1, partialSum+nums[i], partialList, nums, target, rst);
                partialList.remove(partialList.size()-1);
            }
        }
    }
}

A little imporved version:

public List<List<Integer>> fourSum(int[] nums, int target) {
        Arrays.sort(nums);
        return kSum(nums, 0, 4, target);
    }
    private List<List<Integer>> kSum (int[] nums, int start, int k, int target) {
        int len = nums.length;
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        if(k == 2) { //two pointers from left and right
            int left = start, right = len - 1;
            while(left < right) {
                int sum = nums[left] + nums[right];
                if(sum == target) {
                    List<Integer> path = new ArrayList<Integer>();
                    path.add(nums[left]);
                    path.add(nums[right]);
                    res.add(path);
                    while(left < right && nums[left] == nums[left + 1]) left++;
                    while(left < right && nums[right] == nums[right - 1]) right--;
                    left++;
                    right--;
                } else if (sum < target) { //move left
                    left++;
                } else { //move right
                    right--;
                }
            }
        } else {
            for(int i = start; i < len - (k - 1); i++) {
                if(i > start && nums[i] == nums[i - 1]) continue;
                List<List<Integer>> temp = kSum(nums, i + 1, k - 1, target - nums[i]);
                for(List<Integer> t : temp) {
                   t.add(0, nums[i]);
                }                    
                res.addAll(temp);
            }
        }
        return res;
    }

(2) Python

class Solution(object):
    def fourSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        def ksum(nums, target, k):
            rst = []
            if (k == 2):
                left, right = 0, len(nums)-1
                while left < right:
                    total = nums[left]+nums[right]
                    if total == target:
                        rst.append([nums[left], nums[right]])
                        while left < right and nums[left] == nums[left+1]:
                            left += 1
                        while left < right and nums[right] == nums[right-1]:
                            right -= 1
                        left += 1
                        right -= 1
                    elif total < target:
                        left += 1
                    else: 
                        right -= 1
            else:
                for i in xrange(0, len(nums)-k+1):
                    if i != 0 and nums[i] == nums[i-1]:
                        continue
                    lists = ksum(nums[i+1:], target-nums[i], k-1)  
                    if len(lists) > 0:
                        for l in lists:
                            l.append(nums[i])
                            rst.append(l)                    
            return rst

        if not nums or len(nums) <= 3:
            return []
        nums.sort()
        return ksum(nums, target, 4)

(3) Scala

import scala.collection.mutable.ListBuffer

object Solution {
    def fourSum(nums: Array[Int], target: Int): List[List[Int]] = {
        val rst = ListBuffer[List[Int]]()
        if (nums == null || nums.length == 0) {
            return rst.toList
        }
        scala.util.Sorting.quickSort(nums)
        ksum(nums, target, 4, 0, List[Int](), rst)
        return rst.toList
    }

    def ksum(nums: Array[Int], target: Int, k: Int, startIdx: Int, sum: List[Int], rst: ListBuffer[List[Int]]) {
        if (k == 2) {
            twoSum(nums, target, startIdx, sum, rst)
        } else {
            for (i <- startIdx to nums.length-k) {
                if (i == startIdx || nums(i) != nums(i-1)) {
                    ksum(nums, target-nums(i), k-1, i+1, nums(i)::sum, rst)
                }
            }
        }
    }

    def twoSum(nums: Array[Int], target: Int, startIdx: Int, sum: List[Int], rst: ListBuffer[List[Int]]) {
        var left = startIdx;
        var right = nums.length-1
        while (left < right) {
            if (nums(left)+nums(right) == target) {
                val list: List[Int] = nums(left)::nums(right)::sum
                rst += list
                while(left < right && nums(left) == nums(left+1)) {
                    left += 1
                }
                while(left < right && nums(right) == nums(right-1)) {
                    right -= 1
                }
                left += 1
                right -= 1
            } else if (nums(left)+nums(right) < target) {
                left += 1
            } else {
                right -= 1
            }
        }
    }
}

results matching ""

    No results matching ""