https://oj.leetcode.com/problems/combination-sum/

http://fisherlei.blogspot.com/2013/01/leetcode-combination-sum-solution.html

http://blog.csdn.net/linhuanmars/article/details/20828631


public class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target)
    {
        // Solution A
        // return combinationSum_Coin(candidates, target);
        
        // Solution B
        return combinationSum_DP(candidates, target);
    }

    /////////////////////////////
    // Solution B: DP
    //
    private List<List<Integer>> combinationSum_DP(int[] candidates, int target)
    {
        List<List<Integer>> result = new ArrayList<>();
        
        if (candidates == null || candidates.length == 0)
            return result;
        
        // Sort    
        Arrays.sort(candidates);
        
        combinationSum_DP_help(candidates, 0, target, new ArrayList<Integer>(), result);
        return result;
    }
    
    private void combinationSum_DP_help(int[] c, int start, int t, List<Integer> items, List<List<Integer>> result)
    {
        if (t < 0)
            return;
            
        if (t == 0)
        {
            // A result found
            result.add(new ArrayList<Integer>(items));
        }
        
        for (int i = start ; i < c.length ; i ++)
        {
            // 由于输入数组中的元素可以重复使用,
            // 所以在下一次迭代中,start 仍然是 i, 而不是i+1
            // 这是和 Combination Sum II 的区别
            // 
            // 所以当i和i-1 一样时,我们跳过这 组 迭代
            //
            // 否则,输入数组可以进行预处理消除重复,则不需要这个if逻辑
            if (i > 0 && c[i] == c[i - 1])
                continue;
            items.add(c[i]);
            combinationSum_DP_help(c, i, t - c[i], items, result);
            items.remove(items.size() - 1);
        }
    }

    /////////////////////////////
    // Solution A: Coin
    // 
    private List<List<Integer>> combinationSum_Coin(int[] candidates, int target) {
        
        if (candidates == null || candidates.length == 0)
            return Collections.emptyList();    // Invalid input.
        
        // The coin problems.
        // Since same number can be used multiple times.
        // Let sort it and remove dupes.
        List<Integer> c = sortAndDedupe(candidates);
        
        Set<List<Integer>> result = new HashSet<>();
        
        sum(c, target, 0, new ArrayList<Integer>(), result);
        return new ArrayList<>(result);
    }
    
    private void sum(List<Integer> c, int t, int sumsofar, List<Integer> nums, Set<List<Integer>> result)
    {
        if (sumsofar > t)
            return;
            
        if (sumsofar == t)
        {
            // A solution found
            Collections.sort(nums);
            result.add(nums);
            return;
        }
        
        for (int i = c.size() - 1 ; i >= 0 ; i --)
        {
            int v = c.get(i);
            if (sumsofar + v <= t)
            {
                List<Integer> newnums = new ArrayList<>(nums);
                newnums.add(v);
                sum(c, t, sumsofar + v, newnums, result);
            }
        }
    }
    
    private List<Integer> sortAndDedupe(int[] c)
    {
        Set<Integer> set = new HashSet<>();
        for (int i : c)
        {
            set.add(i);
        }
        List<Integer> toReturn = new ArrayList<>(set);
        Collections.sort(toReturn);
        return toReturn;
    }
}