LeetCode – 4Sum (Java)

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

Note:
Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
The solution set must not contain duplicate quadruplets.

    For example, given array S = {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)

Java Solution

A typical k-sum problem. Time is N to the power of (k-1).

public List<List<Integer>> fourSum(int[] nums, int target) {
    List<List<Integer>> result = new ArrayList<List<Integer>>();
 
    if(nums==null|| nums.length<4)
        return result;
 
    Arrays.sort(nums);
 
    for(int i=0; i<nums.length-3; i++){
        if(i!=0 && nums[i]==nums[i-1])
            continue;
        for(int j=i+1; j<nums.length-2; j++){
            if(j!=i+1 && nums[j]==nums[j-1])
                continue;
            int k=j+1;
            int l=nums.length-1;
            while(k<l){
                if(nums[i]+nums[j]+nums[k]+nums[l]<target){
                    k++;
                }else if(nums[i]+nums[j]+nums[k]+nums[l]>target){
                    l--;
                }else{
                    List<Integer> t = new ArrayList<Integer>();
                    t.add(nums[i]);
                    t.add(nums[j]);
                    t.add(nums[k]);
                    t.add(nums[l]);
                    result.add(t);
 
                    k++;
                    l--;
 
                    while(k<l &&nums[l]==nums[l+1] ){
                        l--;
                    }
 
                    while(k<l &&nums[k]==nums[k-1]){
                        k++;
                    }
                }
 
 
            }
        }
    }
 
    return result;
}
Category >> Algorithms  
If you want someone to read your code, please put the code inside <pre><code> and </code></pre> tags. For example:
<pre><code> 
String foo = "bar";
</code></pre>

  1. anon on 2014-4-15

    There is a quadratic algorithm for this: http://stackoverflow.com/questions/14732277/quadratic-algorithm-for-4-sum (read first comment). I suppose that you can solve K-sum in O(N^((K+1)/2)) using the “store (K+1)/2-sums in a hash and then search for a match in the hash” logic.

  2. sammy on 2014-8-29

    Very nice solution! Can you explain why dont you use the same approach as in 3Sum, i.e. to skip repeating numbers with a while check?

  3. CopperCash on 2015-1-11

    I guess that is because if the duplicate check is based on `while` and `index`, it will require 4 check points every loop. Since there is a `set` to make user there is no duplicate, so no need to check with `while`.

  4. Jinyao Xu on 2015-2-3

    One style optimization of your code is that you don’t need to use both hashset and result.
    You just need the hashset.
    Set<List> hashset = new HashSet();
    When you add tuple of 4, do this:
    hashset.add(Arrays.asLists(a, b, c, d)); // pay attention to the desc order

    Then, when you return, do this:
    return new ArrayList<List>(hashset);

    This makes your code clearer

  5. VIVEK VERMA on 2015-2-20

    Shouldn’t it be TreeSet or something instead of ArrayList. The order does matter while comparing one ArrayList to another.

  6. ryanlr on 2015-3-3

    Good idea!

  7. ryanlr on 2015-3-3

    The array is sorted at the beginning.

  8. Jinyao Xu on 2015-4-29

    why not give it a try?

  9. Rohit on 2015-5-26

    For checking duplicate can we do this ?
    whenever we find the match get the sum of the i+j+k+l and store it in arraylist and everytime we find a match we can check if that sum exists in the arraylist if not its a new match or else already found.

  10. Charles Gao on 2016-1-1

    You could simply check if the temp already exist by using result.contains(temp) instead of using HashSet.

  11. Renzo on 2016-2-6
  12. Rahul Nakkanwar on 2016-2-20

    agreed…hashset is not required here

  13. Matias SM on 2016-4-9

    I think you don’t need the Set to avoid duplicates if you check for each idx that the current value is different from the last one used. (same logic used in 3Sum solution)

  14. Stephen Boesch on 2017-3-31

    This is not a comparable solution due to the extra memory requirement.

  15. Vasile on 2017-4-4

    May be I didn’t copy it correctly, but searching for for-sums of 0 through
    an array 0 to 99 gives actually a list of solutions – which is impossible:

    Experiment (invoked in Scala):

    val a = (0 to 100) toArray
    val list = ClassicSolution.fourSum(a, 0)
    //this outputs:
    //list : java.util.List[java.util.List[Integer]] = [[0, 1, 2, 100], [0, 1, 3,
    //| 99], [0, 1, 4, 98], [0, 1, 5, 97], [0, 1, 6, 96], [0, 1, 7, 95], [0, 1, 8,
    //| 94], [0, 1, 9, 93], [0, 1, 10, 92], [0, 1, 11, 91], [0, 1, 12, 90], [0, 1, 1
    //| 3, 89], [0, 1, 14, 88], [0, 1, 15, 87], [0, 1, 16, 86], [0, 1, 17, 85], [0,
    //| 1, 18, 84], [0, 1, 19, 83], [0, 1, 20, 82], [0, 1, 21, 81], [0, 1, 22, 80],
    //| [0, 1, 23, 79], [0, 1, 24, 78], [0, 1, 25, 77], [0, 1, 26, 76], [0, 1, 27, 7
    //| 5], [0, 1, 28, 74], [0, 1, 29, 73], [0, 1, 30, 72], [0, 1, 31, 71], [0, 1, 3
    //| 2, 70], [0, 1, 33, 69], [0, 1, 34, 68], [0, 1, 35, 67], [0, 1, 36, 66], [0,
    //| 1, 37, 65], [0, 1, 38, 64], [0, 1, 39, 63], [0, 1, 40, 62], [0, 1, 41, 61],
    //| [0, 1, 42, 60], [0, 1, 43, 59], [0, 1, 44, 58], [0, 1, 45, 57], [0, 1, 46, 5
    //| 6], [0, 1, 47, 55], [0, 1, 48, 54], [0, 1, 49, 53], [0, 1, 50, 52], [0, 2, 3
    //| , 100], [0, 2, 4, 99], [0, 2, 5, 98], [0, 2, 6, 97], [0, 2, 7, 96], [0, 2, 8
    //| , 95], [0, 2, 9, 94], [0

    Copied solution:

    public class ClassicSolution {

    /**
    * @param target - what the four integers
    * should sum-up together to(typically 0)
    */
    public static List<List> fourSum(int[] nums, int target){

    List<List> result = new ArrayList();

    //if there is no array or if it is smaller then 4
    if(nums == null || nums.length < 4){
    return result;
    }
    Arrays.sort(nums);

    //outer loop
    for (int i = 0; i < nums.length-3; i++) {
    /*
    * if current int is same as previous
    * skip the iteration
    */
    if(i != 0 && nums[i] == nums[i-1]) continue;
    //first inner loop
    for(int j=i+1; j<nums.length-2; j++){
    /*
    * if not the first iteration or
    * f current int is the same as previous
    * skip the iteration
    */
    if(j != i+1 && nums[j] == nums[j-1])
    continue;
    int k = j+1; //current inner loop index + 1
    int l = nums.length-1; //last index of the passed-in array

    /*
    * main logic starts here:
    * increment k until it hits the end of the array
    * remember when we finish we will repeat everything with
    * k+1 on next iteration
    */
    while(k
    * increment k
    */
    if(nums[i]+nums[j]+nums[k]+nums[l] target){
    //if greater then target - decrement l
    l--;
    } else{
    /*
    * save numbers at current indices
    * to a new list -> result list
    */
    List t = new ArrayList();
    t.addAll(Arrays.asList(nums[i],nums[j]
    ,nums[k],nums[l]));
    result.add(t);
    k++;
    l--;

    while(k<l && nums[l] == nums[l+1]){
    l--;
    }

    while(k<l && nums[k] == nums[k-1]){
    k++;
    }
    }
    }
    }

    }
    return result;
    }
    }

Leave a comment

*