39. 组合总和

39. 组合总和 【中等题】【回溯】

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

说明:

  • 所有数字(包括 target)都是正整数。
  • 解集不能包含重复的组合。
输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
  [7],
  [2,2,3]
]

输入: candidates = [2,3,5], target = 8,
所求解集为:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]


题目讲解

方法一

【历史重难点题目】

【思路】

  • candidates[]中的每一个数,都有取和不取两种状态
  • help(candidates,start+1,end,target,list,ans)表示不取
  • help(candidates,start,end,target-candidates[start],list,ans)表示取

【代码】

public List<List<Integer>> combinationSum(int[] candidates, int target) {
    List<List<Integer>> ans=new ArrayList<>();
    help(candidates,0,candidates.length,target,new ArrayList<>(),ans);
    return ans;
}

void help(int[] candidates, int start, int end,int target,List<Integer> list,List<List<Integer>> ans){
    if(target==0){
        ans.add(new ArrayList<>(list));
        return;
    }
    if(start>=end || target<0)
        return;

    help(candidates,start+1,end,target,list,ans);
    list.add(candidates[start]);
    help(candidates,start,end,target-candidates[start],list,ans);
    list.remove(list.size()-1);
}

【备注】

  • 可以用target-candidates[start]>=0的判断条件,做一定的剪枝
public List<List<Integer>> combinationSum(int[] candidates, int target) {
     List<List<Integer>> ans=new ArrayList<>();
     help(candidates,0,candidates.length,target,new ArrayList<>(),ans);
     return ans;
 }

 void help(int[] candidates, int start, int end,int target,List<Integer> list,List<List<Integer>> ans){
     if(target==0){
         ans.add(new ArrayList<>(list));
         return;
     }
     if(start>=end || target<0)
         return;

     help(candidates,start+1,end,target,list,ans);
     if(target-candidates[start]>=0){
         list.add(candidates[start]);
         help(candidates,start,end,target-candidates[start],list,ans);
         list.remove(list.size()-1);
     } 
 }
  • ans.add(new ArrayList<>(list))对于这一行代码有些读者可能有疑问,为什么不能直接ans.add(list)呢?这是一个传值和传引用的问题【点此详见解析】
方法二

【代码】

public List<List<Integer>> combinationSum(int[] candidates, int target) {
    List<List<Integer>> ans = new ArrayList<>();
    if(candidates==null) return ans;
    help(ans,new ArrayList<>(),0,target,candidates);
    return ans;
}
void help(List<List<Integer>> ans,List<Integer> cur,int start,int target,int[] candidates){
    if(target==0){
        ans.add(new ArrayList(cur));
        return;
    }else{
        for(int i=start ; i<candidates.length ; i++){
            if(target-candidates[i]>=0){
                cur.add(candidates[i]);
                help(ans,cur,i,target-candidates[i],candidates);
                cur.remove(cur.size()-1);
            }
        }
    }
}

【备注】

  • 可以先对candidates[]排个序,这样可以做一些剪枝
public List<List<Integer>> combinationSum(int[] candidates, int target) {
    Arrays.sort(candidates);
    List<List<Integer>> ans = new ArrayList<>();
    if(candidates==null) return ans;
    help(ans,new ArrayList<>(),0,target,candidates);
    return ans;
}
void help(List<List<Integer>> ans,List<Integer> cur,int start,int target,int[] candidates){
    if(target==0){
        ans.add(new ArrayList(cur));
        return;
    }
    if(target<0)
        return;
    for(int i=start ; i<candidates.length ; i++){
        if(target-candidates[i]>=0){
            cur.add(candidates[i]);
            help(ans,cur,i,target-candidates[i],candidates);
            cur.remove(cur.size()-1);
        }
        else
            break;
    }
}
  • 帮到你了的话,点个在看吧

关注微信公众号“算法岗从零到无穷”,更多算法知识点告诉你。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值