Leet code-Combination Sum series collation

Keywords: Java less

Combination Sum I

Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
The same repeated number may be chosen from C unlimited number of times.
For example: [2, 3, 6, 7] and target 7

[
  [7],
  [2, 2, 3]
]

Given an array (elements without duplication) and a target value, find all combinations and add up to the target value. Elements in an array can be reused.
Solution:

public class CombinationSum {
    public static List<List<Integer>> combinationSum(int[] candidates, int target){
        Arrays.sort(candidates);
        List<List<Integer>> result = new ArrayList<>();
        getResult(result, new ArrayList<Integer>(), candidates, target, 0);
        return result;
    }

    private static void getResult(List<List<Integer>> result, ArrayList<Integer> current, int[] candidates, int target,
            int start) {
        if(target<0)    return;
        if(target==0){
            result.add(new ArrayList<>(current));
            return;
        }
        for(int i = start; i<candidates.length && target >= candidates[i]; i++){
            current.add(candidates[i]);
            getResult(result, current, candidates, target-candidates[i], i);
            current.remove(current.size() - 1);
        }
    }
    public static void main(String[] args) {
        int[] nums = {2,3,6,7};
        System.out.println(combinationSum(nums, 7));
    }
}

LC40. Combination Sum II

Given an array (elements can be duplicated) and a target value, find all combinations that add up to the target value. Elements in an array cannot be reused.
Example: [10, 1, 2, 7, 6, 1, 5] and target 8

[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

Solution:

/**
 * Remove weight, pay attention to boundaries, and add one to recursion
 */
public class CombinationSum2 {
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(candidates);
        dfs(result, new ArrayList<Integer>(), candidates, target, 0);
        return result;
    }
    
    private void dfs(List<List<Integer>> result, ArrayList<Integer> current, int[] candidates, int target, int start) {
        if(target < 0)  return;
        if(target == 0){
            result.add(new ArrayList<Integer>(current));
            return;
        }
        for(int i = start; i<candidates.length && target >= candidates[i]; i++){
            current.add(candidates[i]);
            dfs(result, current, candidates, target - candidates[i], i+1);    // Note here that i+1, each element can only be used once, and then add one and recurse down.
            current.remove(current.size()-1);
            while(i < candidates.length - 1 && candidates[i] == candidates[i+1]) i++;    // To repeat (note that i+1 is above, length-1 is here, boundary problem)
        }
    }
    public static void main(String[] args) {
        int[] array = {10, 1, 2, 7, 6, 1, 5};
        int target = 8;
        System.out.println(new CombinationSum2().combinationSum2(array, target));
    }
}

LC216. Combination Sum III

Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.

Example 1: Input: k = 3, n = 7

Output: [[1,2,4]]

Example 2: Input: k = 3, n = 9

Output: [[1,2,6], [1,3,5], [2,3,4]]

Given K and N, the sum of these nine numbers from 1 to 9 is N. 1-9 cannot be reused.

/**
 * Note the end condition: size reaches k and the remaining value is 0
 */
public class CombinationSum3 {
    public List<List<Integer>> combinationSum3(int k, int n) {
        List<List<Integer>> result = new ArrayList<>();
        dfs(result, new ArrayList<Integer>(), k, n, 1);
        return result;
    }
    private void dfs(List<List<Integer>> result, ArrayList<Integer> current, int k, int remainder, int start){
        if(current.size() == k && remainder == 0){ //The size reaches k and the residual value is 0.
            result.add(new ArrayList<>(current));
            return ;
        }
        for(int i = start; i<=9 && remainder >= i; i++){
            current.add(i);
            dfs(result, current, k, remainder - i, i+1); // No repetition, i+1
            current.remove(current.size() - 1);
        }
    }
    public static void main(String[] args) {
        System.out.println(new CombinationSum3().combinationSum3(3, 15));
    }
}

LC 377. Combination Sum IV

Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.

Example: nums = [1, 2, 3], target = 4

The possible combination ways are:

(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)

Note that different sequences are counted as different combinations.
Therefore the output is 7.

Follow up: What if negative numbers are allowed in the given array?
How does it change the problem? What limitation we need to add to the
question to allow negative numbers?

If there are negative numbers, you cannot reuse elements in an array.

Given a positive integer array (elements without duplication), given the target, find out the number of combinations, so that the sum of elements in the combination equals the target. Array elements can be reused.

public class CombinationSum4 {
    public int combinationSum4(int[] candidates, int target){
        List<List<Integer>> result = new ArrayList<>();
        dfs(result, new ArrayList<Integer>(), candidates, target, 0);
        return result.size();
    }
    
    private void dfs(List<List<Integer>> result, ArrayList<Integer> current, int[] candidates, int target, int start) {
        if(target < 0)    return;
        if(target == 0){
            result.add(new ArrayList<>(current));
            return;
        }
        for(int i = 0; i<candidates.length && target >= candidates[i]; i++){
            current.add(candidates[i]);
            dfs(result, current, candidates, target-candidates[i], i);
            current.remove(current.size() - 1);
        }
    }
    public static void main(String[] args) {
        int[] arr = {1,2,3};
        System.out.println(new CombinationSum4().combinationSum4(arr, 4));
    }
}

In a recursive call loop, you can modify the starting position of i for the first question: i = 0
But TLE. The recursion depth is too deep.
So this method is not feasible.
You need to use DP.

public int combinationSum4(int[] candidates, int target){
    Arrays.sort(candidates);
    int[] dp = new int[target + 1];
    dp[0] = 1;
    for(int i = 1; i<dp.length; i++){
        for(int curr: candidates){
            if(curr > i)    break;
            dp[i] += dp[i - curr];
        }
    }
    return dp[target];
}

Interview questions: revised version

The Taoist Sutra title is a revised version, which can also return the number of combinations, but with the condition that repetition is removed.
The example above: nums = [1, 2, 3] target = 4, returns 7.
The possible combination ways are: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1)
The Title returns 4. All combinations are: (1, 1, 1, 1), (1, 1, 2), (1, 3), (2, 2), (3, 1).
It becomes the first question: you need to change the return value and return the size.

Take a look at these differences, minor changes, resulting in different results:
Based on the first question Combination Sum I:

public class CombinationSum {
    public static List<List<Integer>> combinationSum(int[] candidates, int target){
        Arrays.sort(candidates);
        List<List<Integer>> result = new ArrayList<>();
        getResult(result, new ArrayList<Integer>(), candidates, target, 0);
        return result;
    }
    
    private static void getResult(List<List<Integer>> result, ArrayList<Integer> current, int[] candidates, int target,
            int start) {
        if(target < 0)    return; // It's possible to be less than zero.
        if(target == 0){
            result.add(new ArrayList<>(current)); // Notice here
            return;
        }
        // Note 1
        for(int i = start; i<candidates.length && target >= candidates[i]; i++){
            current.add(candidates[i]);
            getResult(result, current, candidates, target-candidates[i], i); // Note 2
            current.remove(current.size() - 1);
        }
    }
    public static void main(String[] args) {
        int[] nums = {1,2,3};
        System.out.println(combinationSum(nums, 4));
    }
}

In the above two points of attention:
Question 1: Arrays (elements do not repeat), elements in arrays can be reused. Result

[[1, 1, 1, 1], [1, 1, 2], [1, 3], [2, 2]]

If the first point is changed to i = 0, the result becomes:

[[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1]]

If the first is changed to i = start and the second is changed to i+1, the result becomes:

[[1, 3]]

Posted by android6011 on Tue, 01 Jan 2019 16:42:08 -0800