图解Leetcode组合总和系列——回溯(剪枝优化)+动态规划

本文详细介绍了LeetCode中的组合总和系列问题,包括回溯法(剪枝优化)和动态规划的解决方案。通过示例和解空间树分析,阐述了如何解决组合总和I到IV的问题,提供了Java和Go语言的代码实现。
摘要由CSDN通过智能技术生成

Leetcode组合总和系列——回溯(剪枝优化)+动态规划

组合总和 I

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

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

说明:

所有数字(包括 target)都是正整数。
解集不能包含重复的组合。

示例 1:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum

此题要求解出所有可能的解,则需要用回溯法去回溯尝试求解,我们可以画一棵解空间树:

在这里插入图片描述

​ 图中绿色节点表示找到了一种可行解,而红色的节点表示到这个节点的时候组合总和的值已经大于target了,无需继续向下尝试,直接返回即可。

​ 因为题目要求解集无重复,即2,2,33,2,2应该算作同一种解,所以我们在回溯的时候应该先对candidates数组排序,然后每次只向下回溯大于等于自己的节点。

​ 观察解空间树我们发现:当某一层中第一次出现红色节点或绿色节点后,后面的节点将全变为红色,因为数组是经过排序的,任意节点后面的节点都是大于此节点的(candidates数组无重复元素),所以当出现一个红/绿色节点后,后面的节点不必再继续检查,直接剪枝即可。

剪枝后的解空间树如下:

在这里插入图片描述

这样看整棵解空间树就小多了,下面直接上代码:

Java版本的回溯解法代码

class Solution {
   

    List<List<Integer>> result = new ArrayList<>();

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
   
        Arrays.sort(candidates);
        dfs(candidates,target,0,new ArrayList());
        return result;
    }

    public void dfs (int[] candidates, int target, int currSum, List<Integer> res) {
   
        if (currSum == target) {
   
            result.add (new ArrayList(res));
            return;
        }
        for (int i = 0; i < candidates.length; i++) {
   
            if (currSum + candidates[i] > target) {
   
                return;
            }
            int size = res.size();
            if (size==0 || candidates[i] >= res.get(size-1)) {
   
                res.add(candidates[i]);
                dfs(candidates, target, currSum+candidates[i],res);
                res.remove(size);
            }
        }
    }
}

Go版本的回溯解法代码

func combinationSum(candidates []int, target int) (result [][]int) {
   
    sort.Ints(candidates)
	var dfs func(res []int, currSum int)
	dfs = func(res []int, currSum int) {
   
		if currSum == target {
   
			result = append(result, append([]int(nil), res...))
			
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值