Leet code -- Combination Sum系列整理

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.
例如: [2, 3, 6, 7] and target 7面試

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

給定一個數組(元素無重複),和一個目標值,找到全部組合,加起來等於目標值。數組中的元素能夠重複使用.
解法:數組

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

給定一個數組(元素能夠有重複),和一個目標值,找到全部組合,加起來等於目標值。數組中的元素不能重複使用。
例子: [10, 1, 2, 7, 6, 1, 5] and target 8code

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

解法:遞歸

/**
 * 要去重,注意邊界,遞歸時候要加一
 */
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);    // 此處注意i+1,每一個元素只能用一次,加一後在向下遞歸
            current.remove(current.size()-1);
            while(i < candidates.length - 1 && candidates[i] == candidates[i+1]) i++;    // 去重複(注意上面有i+1,這裏要length-1,邊界問題)
        }
    }
    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.rem

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

Output: [[1,2,4]]

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

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

給定K和N,從1--9中這幾個9個數字組合出來K個數,其和爲N。1-9不能重複使用.io

/**
 * 注意結束條件:size達到k值 而且 剩餘值爲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){ //size達到k值 而且 剩餘值爲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); // 不重複,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.class

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?

若是有負數,就不能讓數組中的元素重複使用。

給定一個正整數數組(元素無重複),給定目標target,找出組合的個數,使得組合中元素的和等於target。數組元素能夠重複使用.

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));
    }
}

遞歸調用循環中,對於第一題修改i的起始位置便可:i = 0
可是TLE。遞歸深度太深。
因此這個方法是不行的。
須要使用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];
}

面試題:修改版

有道面經題目是一個修改版,也是返回組合個數便可,可是加了條件:去掉重複。
上面的例子:nums = [1, 2, 3] target = 4 ,返回 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)
這個題目要返回的是4,全部的組合是:(1, 1, 1, 1) (1, 1, 2) (1, 3) (2, 2) (3, 1)
變成第一題了:須要改變返回值,返回大小便可。

看一下這幾個的區別,輕微的改動,產生的不一樣結果:
以第一題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; // 是有可能小於0的
        if(target == 0){
            result.add(new ArrayList<>(current)); // 此處注意
            return;
        }
        // 注意點1
        for(int i = start; i<candidates.length && target >= candidates[i]; i++){
            current.add(candidates[i]);
            getResult(result, current, candidates, target-candidates[i], i); // 注意點2
            current.remove(current.size() - 1);
        }
    }
    public static void main(String[] args) {
        int[] nums = {1,2,3};
        System.out.println(combinationSum(nums, 4));
    }
}

在上面的兩個注意點上:
第一題:數組(元素無重複),數組中的元素能夠重複使用。結果

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

若是第一處修改爲 i = 0 結果變爲:

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

若是第一處修改成 i = start 以及 第二處修改成 i+1 結果變爲:

[[1, 3]]
相關文章
相關標籤/搜索