LeetCode HOT 100:组合总和

时间:2022-12-13 21:10:31

题目描述:

给你一个没有重复元素的数组,和一个target目标值,返回数组中可以使数字和为目标数target所有不同组合。什么叫组合?组合就是数组中任意数字组成的集合,不需要连续,组合和顺序无关。这一题中的不同,指的是两个组合中至少一个数字的被选数量不同,例如[2, 3, 3][2, 3, 2]就是同一个组合,反之则是不同。

思路:

这道题是很典型的回溯。回溯其实就是穷举,最多加点剪枝优化一下。所以这题思想就很简单,把每个元素不断穷举,判断其和是否达到了target

步骤:

本题主要是回溯方法怎么写,所以下面步骤是回溯方法的步骤。
1、先定义好回溯方法的入参
这一题入参也很简单,数组,还需要凑齐的和,要从哪个下标开始穷举
2、定义好回溯方法后,方法里首先确定回溯结束的条件
这一题回溯结束条件就是:还需要凑齐的和为0了,说明该终止本次回溯了
3、定义好终止条件,下面就是开始穷举,伪代码如下

for (int i = startIndex; i < candidates.length; i++) {
	将元素放入数组
	迭代回溯方法
	将元素从数组中删除,回溯
}

解释:

1、本题使用了回溯模版,可以解决很多类似问题,回溯模版在这里总结一下。

void process(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本次递归集合中元素(从开始下标到数组结尾)) {
        处理节点;
        process(参数); // 递归
        回溯,撤销处理结果
    }
}

代码:

    List<List<Integer>> ans;
    List<Integer> list;

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        ans = new ArrayList<>();
        list = new ArrayList<>();

        // 从下标0开始,需要凑齐target的数
        process(candidates, target, 0);

        return ans;
    }

    // rest:剩下要凑齐的数字
    // startIndex:从哪个下标开始,继续拿值尝试
    public void process(int[] candidates, int rest, int startIndex) {
        // 剩余要凑的数字为0,说明target已经达到了,放进结果集合中
        if (rest == 0) {
            ans.add(new ArrayList<>(list));
            return;
        }

        // 从startIndex下标开始取值尝试
        for (int i = startIndex; i < candidates.length; i++) {
            // 如果当前值 > 剩下要凑齐的数字,那这个值就不用考虑了
            if (candidates[i] <= rest) {
                // 先将值放进数组
                list.add(candidates[i]);
                // 去递归找剩下要凑齐的rest - candidates[i]值
                // 因为每个数可以无限取,所以下次尝试还是从 i 开始,而不是 i + 1
                process(candidates, rest - candidates[i], i);
                // 将刚才放进去的值删除,回溯
                list.remove(list.size() - 1);
            }
        }
    }