Leetcode39 Combination Sum

Combination Sum

Given a set of candidate numbers (C) 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.

Note:

  • All numbers (including target) will be positive integers.
  • Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
  • The solution set must not contain duplicate combinations.

For example, given candidate set 2,3,6,7 and target 7,
A solution set is:
[7]
[2, 2, 3]

Solution1

  • 这是一道典型的回溯题。每次都尝试加入一个数,若当前得到的和还不够,则继续加入该数,直到和大于target,如果和等于target则得到一个解,若大于则回溯一个数,然后尝试数组中的下一个数。
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
public class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        Arrays.sort(candidates);
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        help(candidates,0,target,result,new ArrayList<Integer>());
        return result;
    }
    public void help(int[] candidates,int index,int target,List<List<Integer>> result,List<Integer> item){
        if(target==0){
            result.add(item);
            return;
        }
        if(target<0||index>=candidates.length) return;
        for(int i=index;i<candidates.length;i++){
            if(target<candidates[i]) return;//因为数组已经排过序,所以后面的数都没必要再去遍历
            List<Integer> temp = new ArrayList<Integer>(item);
            temp.add(candidates[i]);
            help(candidates,i,target-candidates[i],result,temp);
        }        
    }
}

Solution2

  • 理论上,任何递归解法都可以用迭代解法来实现,而迭代一般要借用栈的实现,这里就是用一个栈来记录存入数组中的下标。
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        Arrays.sort(candidates);
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        List<Integer> item = new ArrayList<Integer>();
        Stack<Integer> indexes = new Stack<Integer>();
        for(int i=0,sum=0;i<candidates.length||!indexes.empty();){ 
            if(i<candidates.length){
                while(sum+candidates[i]<target){
                    sum += candidates[i];
                    indexes.push(i);
                    item.add(candidates[i]);
                }
                if(sum+candidates[i]==target){
                    List<Integer> item1 = new ArrayList<Integer>(item);
                    item1.add(candidates[i]);
                    result.add(item1);
                }
            }
            if(indexes.empty()) return result;
            i = indexes.pop();
            sum -= candidates[i++];
            item.remove(item.size()-1);
        }
        return result;      
    }
}

Solution3

  • 这道题实际和找零钱问题本质上是一样的,而找零钱是一个典型的动态规划的解法,因此本题可以用动态规划来解
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap;
public class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        ArrayList<List<Integer>> result = new ArrayList<List<Integer>>();
        if(candidates.length==0) return result;
        result.add(new ArrayList<Integer>());
        HashMap<Integer,List<List<Integer>>> dp = new HashMap<Integer,List<List<Integer>>>();
        dp.put(0,result);
        Arrays.sort(candidates);
        for(int sum=candidates[0];sum<=target;sum++){
            result = new ArrayList<List<Integer>>();
            for(int i=candidates.length-1;i>=0;i--){
                if(!dp.containsKey(sum-candidates[i])) continue;
                for(List<Integer> item:dp.get(sum-candidates[i])){
                    if(item.size()>0&&candidates[i]<item.get(item.size()-1)) continue;//只将升序的序列加入,解决序列重复问题
                    ArrayList<Integer> temp = new ArrayList<Integer>(item);
                    temp.add(candidates[i]);
                    result.add(temp);
                }
                if(i == candidates.length-1) dp.remove(sum-candidates[i]);//将不再需要的去掉,更节省空间
            }
            if(!result.isEmpty()) dp.put(sum,result);
        }
        return dp.get(target)==null?new ArrayList<List<Integer>>():dp.get(target);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值