leetcode-组合总和

788 阅读2分钟

这是我参与8月更文挑战的第28天,活动详情查看:8月更文挑战

周四跟同事说起梭子蟹,当时就很想吃。到了周六,起个大早去买一些尝尝。
上上周六想早起做题了,不过后来还是没起来,果然只有美食才能让人早起。
精进技术不能断,今天继续做leetcode的第39题。

题目

给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。
candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是唯一的。 
对于给定的输入,保证和为 target 的唯一组合数少于 150 个。

示例 1:
输入: candidates = [2,3,6,7], target = 7
输出: [[7],[2,2,3]]

示例 2:
输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

示例 3:
输入: candidates = [2], target = 1
输出: []

示例 4:
输入: candidates = [1], target = 1
输出: [[1]]

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

思路

其实本题是一道背包问题,就是需要恰好把背包用完,而且每件物品可以无限次使用的那一类。常见的背包问题,之前看过cui的背包九讲,对初学者来说,应该算是讲的非常透彻的。
不过本题可以用深度搜索+回溯来解决:对于数组中的每个数组,可以选择用或者不用,如果用,因为可以重复使用,深度优先遍历的时候,还是会回到本处,如果不用,那就继续看下一个数字,同样可以选择用或者不用,直到用的数字和大于等于target为止,如果刚好等于,就是其中1组解,如果大于,那就不是解,不过也不需要继续再遍历下去了。
由于题目保证了数组中数字不重复,所以结果必然是不重复的,不需要最后再做一次去重。
当然,上述算法还有一个常数级别的小优化,可以先把数组排序,那么在进行搜索的时候,如果遍历到n,和大于target,那么后面的就不需要再遍历了,因为和肯定会大于target。

Java版本代码

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        int len = candidates.length;
        if (len == 0) {
            return combinationSumList;
        }
        combinationSumList = new ArrayList<>();
        stack = new Stack<>();
        combinationSumDfs(candidates, 0, target);
        return combinationSumList;
    }

    private static List<List<Integer>> combinationSumList = null;
    private static Stack<Integer> stack = null;

    private static void combinationSumDfs(int[] candidates, int start, int target) {
        if (target == 0) {
            combinationSumList.add(new ArrayList<>(stack));
            return;
        }
        int len = candidates.length;
        if (start >= len) {
            return;
        }
        for (int i = start; i < len; i++) {
            if (candidates[i] <= target) {
                stack.push(candidates[i]);
                combinationSumDfs(candidates, i, target - candidates[i]);
                stack.pop();
            }
        }
    }
}