4sum implementation in Java from leetcode

前端 未结 6 765
生来不讨喜
生来不讨喜 2021-01-07 11:50

The problem statement from leetcode says:

Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Fin

相关标签:
6条回答
  • 2021-01-07 11:57

    Your solution may have exceeded the time limit and therefore may have not been able to pass the test cases. Below is the code having the runtime O(n^3). Initially, we sort the array which will help us to find the element either by moving forward or backward depending on the number we are looking for. We then take the first element from the array and perform a three sum on the remaining part leading to find the two sum. Only the ArrayList is used. HashMap is not required.

    public static 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; //Avoid duplicate elements
    
            for(int j=i+1; j<nums.length-2; j++)
            {
                if(j!=i+1 && nums[j]==nums[j-1]) continue; //Avoid duplicate elements
    
                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;
    }
    
    0 讨论(0)
  • 2021-01-07 11:58
    public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
        Arrays.sort(num);
        ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>();
        int i=0;
        while(i<num.length-3){
            int j=i+1;
            while(j<num.length-2){
                int left=j+1, right=num.length-1;
                while(left<right){
                    if(num[left]+num[right]==target-num[i]-num[j]){
                        ArrayList<Integer> t=new ArrayList<Integer>();
                        t.add(num[i]);
                        t.add(num[j]);
                        t.add(num[left]);
                        t.add(num[right]);
                        res.add(t);
                        left++;
                        right--;
                        while(left<right && num[left]==num[left-1])
                            left++;
                        while(left<right && num[right]==num[right+1])
                            right--;
                    }else if(num[left]+num[right]>target-num[i]-num[j])
                        right--;
                    else
                        left++;
                }
                j++;
                while(j<num.length-2 && num[j]==num[j-1])
                    j++;
            }
            i++;
            while(i<num.length-3 && num[i]==num[i-1])
                i++;
        }
        return res;
    }
    
    0 讨论(0)
  • 2021-01-07 11:59

    Here is an O(n^3) solution

    import java.util.Arrays;
    import java.util.ArrayList;
    import java.util.HashSet;
    public class Solution {
    public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
        // Start typing your Java solution below
        // DO NOT write main() function
    
        Arrays.sort(num);
        HashSet<ArrayList<Integer>> hSet = new HashSet<ArrayList<Integer>>();
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        for (int i = 0; i < num.length; i++) {
            for (int j = i + 1; j < num.length; j++) {
                for (int k = j + 1, l = num.length - 1; k < l;) {
                    int sum = num[i] + num[j] + num[k] + num[l];
                    if (sum > target) {
                        l--;
                    }
                    else if (sum < target) {
                        k++;
                    }
                    else if (sum == target) {
                        ArrayList<Integer> found = new ArrayList<Integer>();
                        found.add(num[i]);
                        found.add(num[j]);
                        found.add(num[k]);
                        found.add(num[l]);
                        if (!hSet.contains(found)) {
                            hSet.add(found);
                            result.add(found);
                        }
    
                        k++;
                        l--;
    
                    }
                }
            }
        }
        return result;
    }
    

    }

    0 讨论(0)
  • 2021-01-07 12:04

    You solution is obviously calculating correctly. But if a value appears several times in the input array there will be given "same" results. Maybe that was tested.

    The "twoSum" of num = { 1, 3, 1, 3, 4 } with target = 4 would be:

    • { 1, 3 }
    • { 1, 3 }
    • { 3, 1 }
    • { 1, 3 }

    It this was the reason for failing in tests, the solution would probably be a set of an ordered list.

    If also subsets must be given, { 4 } is missing.

    So the question is, why did the tests fail, what are the requirements.

    An optimisation probably involves special data structures: at least a (reverse) sorted num. Many links are already given. Recursion can help to find an provable and understandable optimal solution, with pre and post conditions. (As you are splitting the problem.)

    One solution would be be creating pairs keeping a mapping of pair sum to all pairs of indices leading to that sum. And then find two pairs with disjunct indices.


    As no one gave a satisfactory answer:

    A simple recursive solution (not very nice or optimal). However it demonstrates that data structures are relevant.

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.SortedSet;
    import java.util.TreeSet;
    
    public class FourSumSolution {
    
        private static class SortedTuple implements Comparable<SortedTuple> {
            int[] values;
    
            public SortedTuple(int... values) {
                this.values = Arrays.copyOf(values, values.length);
                Arrays.sort(this.values);
            }
    
            public int size() {
                return values.length;
            }
    
            public int get(int index) {
                return values[index];
            }
    
            public ArrayList<Integer> asList() {
                // Result type is ArrayList and not the better List,
                // because of the external API of the outer class.
                ArrayList<Integer> list = new ArrayList<Integer>(values.length);
                for (int value: values)
                    list.add(value);
                return list;
            }
    
            @Override
            public int hashCode() {
                final int prime = 31;
                int result = 1;
                result = prime * result + Arrays.hashCode(values);
                return result;
            }
    
            @Override
            public boolean equals(Object obj) {
                if (this == obj)
                    return true;
                if (obj == null)
                    return false;
                if (getClass() != obj.getClass())
                    return false;
                SortedTuple other = (SortedTuple) obj;
                if (!Arrays.equals(values, other.values))
                    return false;
                return true;
            }
    
            @Override
            public int compareTo(SortedTuple other) {
                int c = cmp(values.length, other.values.length);
                if (c == 0) {
                    for (int i = 0; i < values.length; ++i) {
                        c = cmp(values[i], other.values[i]);
                        if (c != 0)
                            break;
                    }
                }
                return c;
            }
    
            @Override
            public String toString() {
                return Arrays.toString(values);
            }
    
            private static int cmp(int lhs, int rhs) {
                return lhs < rhs ? -1 : lhs > rhs ? 1 : 0; // Cannot overflow like lhs - rhs.
            }
        }
    
        public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
            final int nTerms = 4;
            SortedTuple values = new SortedTuple(num);
            SortedSet<SortedTuple> results = new TreeSet<SortedTuple>();
            int[] candidateTerms = new int[nTerms];
            int valuesCount = values.size();
            solveNSum(target, nTerms, values, results, candidateTerms, valuesCount);
    
            ArrayList<ArrayList<Integer>> aList = new ArrayList<ArrayList<Integer>>();
            for (SortedTuple solution: results) {
                aList.add(solution.asList());
            }
            return aList;   
        }
    
        public static void main(String[] args) {
            final int[] num = { 1, 3, 1, 3, 4 };
            final int requiredSum = 4;
            final int nTerms = 2;
    
            SortedTuple values = new SortedTuple(num);
            SortedSet<SortedTuple> results = new TreeSet<SortedTuple>();
            int[] candidateTerms = new int[nTerms];
            int valuesCount = values.size();
            solveNSum(requiredSum, nTerms, values, results, candidateTerms, valuesCount);
    
            System.out.println("Solutions:");
            for (SortedTuple solution: results) {
                System.out.println("Solution: " + solution);
            }
            System.out.println("End of solutions.");
        }
    
        private static void solveNSum(int requiredSum, int nTerms, SortedTuple values, SortedSet<SortedTuple> results, int[] candidateTerms, int valuesCount) {
            if (nTerms <= 0) {
                if (requiredSum == 0)
                    results.add(new SortedTuple(candidateTerms));
                return;
            }
            if (valuesCount <= 0) {
                return;
            }
    
            --valuesCount;
            int candidateTerm = values.get(valuesCount);
    
            // Try with candidate term:
            candidateTerms[nTerms - 1] = candidateTerm;
            solveNSum(requiredSum - candidateTerm, nTerms - 1, values, results, candidateTerms, valuesCount);
    
            // Try without candidate term:
            solveNSum(requiredSum, nTerms, values, results, candidateTerms, valuesCount);
        }
    }
    

    One can prune this further:

    • Skip the candidate term if the (nTerms - 1) lowest plus the candidate terms give a too large sum;
    • terminate if the candidate term plus the next (nTerms -1) terms are too small.
    • terminate if valuesCount < nTerms
    0 讨论(0)
  • 2021-01-07 12:12

    public class FourSum {

    private static int countFourSum(int[] numbers) {
        int count = 0;
        for (int j = 0; j < numbers.length; j++) {
            for (int i = j + 1; i < numbers.length; i++) {
                int front = i + 1, rear = numbers.length - 1;
    
                while (front < rear) {
                    if (numbers[front] + numbers[rear] + numbers[i] + numbers[j] == 0) {
                        System.out.printf(String.format("{%d} : {%d} : {%d} : {%d}  \n", numbers[front], numbers[rear],
                                numbers[j], numbers[i]));
                        front++;
                        rear--;
                        count++;
                    } else {
                        if (Math.abs(numbers[front]) > Math.abs(numbers[rear])) {
                            front++;
                        } else {
                            rear--;
                        }
                    }
                }
            }
    
        }
        return count;
    }
    
    public static void main(String[] args) {
        int[] numbers = { 1, 2, 3, 4, -4, -5, -6, 2, 4, -1 };
        Arrays.sort(numbers);
        System.out.println(countFourSum(numbers));
    }
    

    }

    0 讨论(0)
  • 2021-01-07 12:23

    Here's a solution that does not use hash. It should be faster, but it still exceeds the time limit.

    import java.util.ArrayList;
    
    public class Solution {
        public static void main(String[] args) {
    
          int[] S = {1, 0, -1, 0, -2, 2};
          int target = 0;
          test(S, target);
        }
    
        public static void test(int[] num, int target) {
          System.out.print("a:");
          for (int i : num) {
            System.out.print(" " + i);
          }
          System.out.println(": " + target);
          ArrayList<ArrayList<Integer>> res = fourSum(num, target);
          for (ArrayList<Integer> list : res) {
            System.out.println(list);
          }
          System.out.println();
        }
    
        // a+b+c+d = target
        public static ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
            // Start typing your Java solution below
            // DO NOT write main() function
    
           // Sort
           {
            for (int i = 0; i < num.length; i++) {
                for (int j = i + 1; j < num.length; j++) {
                    if (num[j] < num[i]) {
                        int tmp = num[i];
                        num[i] = num[j];
                        num[j] = tmp;
                    }
                }
            }
           }
          ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
          int i = 0;
          while (i < num.length - 3) {
            int j = i + 1;
            while (j < num.length - 2) {
                int k = j + 1, l = num.length - 1;
                while (k < l) {
                    int sum = num[i] + num[j] + num[k] + num[l];
                    if (sum > target) {
                        l--;
                        while (k < l && num[l] == num[l+1]) l--;
                    } else if (sum < target) {
                        k++;
                        while (k < l && num[k] == num[k-1]) k++;
                    } else {
                        ArrayList<Integer> list =
                            new ArrayList<Integer>(4);
                        list.add(num[i]); list.add(num[j]);
                        list.add(num[k]); list.add(num[l]);
                        res.add(list);
                        k++;
                        while (k < l && num[k] == num[k-1]) k++;
                        l--;
                        while (k < l && num[l] == num[l+1]) l--;
                    }
                }
                j++;
                while (j < num.length && num[j] == num[j-1]) j++;
            }
            i++;
            while (i < num.length && num[i] == num[i-1]) {
                i++;
            }
          }
    
          return res;
        }
    }
    
    0 讨论(0)
提交回复
热议问题