LeetCode 39 组合总和

LeetCode 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 = [2,3], target = 5,
所求解集为:
[
[2,3]
]

题目解析

要求得出所有和为目标值的组合,那么这样使用回溯法将所有结果遍历一边是非常合适的。

数组中所有元素都是可以重复使用的,那么也就是说每次都可以从第一位开始,但是最终结果中不允许包括重复的组合,那么应该怎样解决呢,那就要将每组数据的第一个值的索引传递进去,每一次都是从这个位置开始判断,那么就可以避免将之前的元素重复使用了。

回溯法

回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

代码实现

最难的地方应该是回溯点的确定和递归的使用

/**
 * @description:给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的数字可以无限制重复被选取。
 * @author: cuiyang
 * @date: 2020/5/19 10:53
 */
// 39. 组合总和
// https://leetcode-cn.com/problems/combination-sum
// 时间复杂度:O(n)
// 空间复杂度:O(n)
public class Solution {
    //全局变量,保存结果集
    static List<List<Integer>> result = new ArrayList<>();

    public static List<List<Integer>> combinationSum(int[] candidates, int target) {
        Arrays.sort(candidates);
        //排序之后,进行数组循环,从前向后依次进行组合,调用dfs方法
        for (int i = 0; i < candidates.length; i++) {
            //单个结果List
            ArrayList<Integer> resultList = new ArrayList<>();
            resultList.add(candidates[i]);
            dfs(candidates, target, candidates[i], resultList, i);
        }
        return result;
    }

    /**
     * 给定数组,目标值,和,单个结果集,计算开始位置
     *
     * @param candidates
     * @param target
     * @param val
     * @param r
     * @param j
     */
    private static void dfs(int[] candidates, int target, int val, List<Integer> r, int j) {
        //回溯点
        if (target == val) {
            result.add(new ArrayList<>(r));
            return;
        }
        //回溯点
        if (val > target) {
            return;
        }
        for (int i = j; i < candidates.length; i++) {
            //数字可重复使用,所有从当前最小的开始累加
            r.add(candidates[i]);
            val += candidates[i];
            //此处未回溯时i始终不变,相当于重复加同一个数
            dfs(candidates, target, val, r, i);
            //r退一步,退到上一步的状态继续执行
            r.remove(r.size() - 1);
            val -= candidates[i];
        }
    }

    public static void main(String[] args) {
        List<List<Integer>> lists = combinationSum(new int[]{2, 3, 6, 7}, 7);
        lists.forEach(l->{
            System.out.println(l.toString());
        });
    }
}

步骤解析

在这里插入图片描述
此处将一小部分的步骤写出,初次写算法类文章,多多指教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值