leetCode40组合总和(回溯)

题目

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次

示例 :

输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]

回溯一般模板

1、会使用深度优先遍历的递归

2、数据是否排序

(1)如果不允许数据重复,要先对数组进行排序,递归的时候,起始节点=当前的index+1,而且

同层相同元素不重复执行

(2)数据允许重复,不用对数组排序,递归的时候,起始节点=当前的index

3、完全递归,把数据恢复到上一个状态,也就是回溯

模板总结

参数说明:

start开始的数组下标
candidates数组
sum达到的条件(这里以数据和为例),具体的按题目要求换

 resultList

所有结果
path中间过程,符合要求的一组数据

允许数据重复一般模板

public static void dfsNum(int start, int[] candidates, int target, int sum, List<List<Integer>> resultList, List<Integer> path) {
    if (结束递归条件) {
        return;
    }
    if (符合要求数据条件) {
        resultList.add(new ArrayList<>(path));
        return;
    }
    for (int i = start; i < candidates.length; i++) {
        if (剪枝条件) {
            break;
        }
        sum += candidates[i];
        path.add(candidates[i]);
        dfsNum(i, candidates, target, sum, resultList, path);
         //回溯,过程中使用的数据,恢复原值
        path.remove(path.size() - 1);
        sum -= candidates[i];
    }
}

不允许数据重复一般模板

public static void dfsNum(int start, int[] candidates, int target, int sum, List<List<Integer>> resultList,List<Integer> path) {
 if (结束递归条件) { return; } 
 if (符合要求数据条件) {
    resultList.add(new ArrayList<>(path)); 
     return; 
}
    for (int i = start; i < candidates.length; i++) {
        //最外层重复数据不重复执行
        if (i > start && candidates[i] == candidates[i - 1]) {
            continue;
        }
        if (剪枝条件) {
            break;
        }
        sum += candidates[i];
        path.add(candidates[i]);
        dfsNum(i + 1, candidates, target, sum, resultList, path);
 //回溯,过程中使用的数据,恢复原值
        path.remove(path.size() - 1);
        sum -= candidates[i];
    }
}

实现代码

public class ArrayZhSum40 {

    public static void main(String[] args) {
        int[] candidates = {2, 5, 2, 1, 2};
        List<List<Integer>> resultList = combinationSum2(candidates, 5);
        System.out.println(JSON.toJSONString(resultList));
        candidates = new int[]{10, 1, 2, 7, 6, 1, 5};
        resultList = combinationSum2(candidates, 8);
        System.out.println(JSON.toJSONString("---" + resultList));
    }


    public static List<List<Integer>> combinationSum2(int[] candidates, int target) {
        if (candidates == null || candidates.length == 0) {
            return null;
        }
        Arrays.sort(candidates);
        List<List<Integer>> resultList = new ArrayList<>();
        dfsNum(0, candidates, target, 0, resultList,
                new ArrayList<Integer>());
        return resultList;
    }

    public static void dfsNum(int start, int[] candidates, int target, int sum, List<List<Integer>> resultList,
                              List<Integer> path) {
        if (target < sum) {
            return;
        }
        if (target == sum) {
            resultList.add(new ArrayList<>(path));
            return;
        }
        for (int i = start; i < candidates.length; i++) {
           //分层中使用过的元素直接不在用
            if (i > start && candidates[i] == candidates[i - 1]) {
                continue;
            }
            if (candidates[i] > target) {
                break;
            }
            sum += candidates[i];
            path.add(candidates[i]);
            //叶子中,不使用已经使用过的元素
            dfsNum(i + 1, candidates, target, sum, resultList, path);
            path.remove(path.size() - 1);
            sum -= candidates[i];
        }
    }


}
  • 22
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值