leetcode题解-40. Combination Sum II && 216. Combination Sum III

来源:互联网 发布:美橙域名查询 编辑:程序博客网 时间:2024/05/17 21:18

40,题目:

Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.Each number in C may only be used once in the combination.Note:All numbers (including target) will be positive integers.The solution set must not contain duplicate combinations.For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8, A solution set is: [  [1, 7],  [1, 2, 5],  [2, 6],  [1, 1, 6]]

本题与上一题Combination Sum基本上是一样的,不同的是这里的数组可能包含重复的数字,但是在求和的过程中不能重复使用数组里的元素。所以首先我们使用上道题目的思路,直接使用回溯法,但是为了解决数组元素不能重复使用的问题,我们需要做一些小的修改,代码如下所示,有两证改进办法:

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {        List<List<Integer>> res = new ArrayList<>();        Arrays.sort(candidates);        dfs(candidates, res, new ArrayList<>(), target, 0);        return res;    }    public void dfs(int[] candidates, List<List<Integer>> res, List<Integer> tmp, int target, int idx){        if(target<0)            return;        else if(target == 0) {        //第一种方法,在将list添加到res之前判断re中是否已经包含,比较直观            if(!res.contains(tmp))                res.add(new ArrayList<>(tmp));        }        else{            for(int i=idx; i<candidates.length; i++) {                //第二种方法,在遍历的过程中加一个判断语句,看前后元素是否相等,如果想等的话则跳过                //if(i > idx && candidates[i] == candidates[i-1]) continue;                tmp.add(candidates[i]);                //此外,为了不使用重复元素,在递归调用时直接将idx+1即可;                dfs(candidates, res, tmp, target-candidates[i], i+1);                tmp.remove(tmp.size()-1);            }        }    }

此外,还有一种改进的方法,这种方法在循环过程中加入了判断语句,可以省去一些不必要的循环。如下所示:

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {        Arrays.sort(candidates);        List<List<Integer>> results = new ArrayList<>();        calcCombinationSum2(candidates, 0, new int[candidates.length], 0, target, results);        return results;    }    private void calcCombinationSum2(int[] candidates, int cindex, int[] list, int lindex, int target, List<List<Integer>> results) {        if (target == 0) {            List<Integer> result = new ArrayList<>();            for (int i = 0; i < lindex; i++) {                result.add(list[i]);            }            results.add(result);            return;        }        int prev = 0;        for (int i = cindex; i < candidates.length; i++) {            if (candidates[i] != prev) {                if (target - candidates[i] < 0) {                    break;                }                list[lindex] = candidates[i];                calcCombinationSum2(candidates, i + 1, list, lindex + 1, target - candidates[i], results);                prev = candidates[i];            }        }    }

216, Combination Sum III,题目:

Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.Example 1:Input: k = 3, n = 7Output:[[1,2,4]]Example 2:Input: k = 3, n = 9Output:[[1,2,6], [1,3,5], [2,3,4]]

这道题目相比前两道就简单了,因为只是求1-9之间和为n的k个数,且不可重复使用。首先仍然使用上述思路,使用回溯法,不同的是,这次既要求元素不可重复使用,又规定了k个数求和的限定条件。所以我们按照下述方法进行修改即可:

    public static List<List<Integer>> combinationSum3(int k, int n) {        List<List<Integer>> res = new ArrayList<>();        int[] nums = {1,2,3,4,5,6,7,8,9};        dfs(nums, res, new ArrayList<>(), n, k, 0);        return res;    }    public static void dfs(int[] nums, List<List<Integer>> res, List<Integer> tmp, int target, int k, int index){    //加上k个数的限制,每加一个数,k减1        if(k < 0 || target < 0)            return;        else if(k == 0 && target == 0){            res.add(new ArrayList<>(tmp));            return;        }else{            for(int i=index; i<nums.length; i++) {                tmp.add(nums[i]);                dfs(nums, res, tmp, target - nums[i], k - 1, i + 1);                tmp.remove(tmp.size()-1);            }        }    }

此外我们还可以不用回溯法,直接使用循环的方式求解,代码入下:

public List<List<Integer>> combinationSum3(int k, int n) {    return helper2(k, n, 9);}private List<List<Integer>> helper2(int k, int n, int end) {    List<List<Integer>> collection = new ArrayList<List<Integer>>();    //用于记录一次成功的结果    int[] sum = new int[k];    while (true) {        //首先,将1-9分配到sum中,便利所有可能组合,要求是k个数和为n        while (k > 0 && n > 0 && end > 0) {            end = end < n ? end : n;            sum[(k--) - 1] = end;            n -= end--;        }        //如果上面的循环满足了k==0且n==0,则将sum记录到res中        if (k == 0 && n == 0) {            List<Integer> list = new ArrayList<Integer>();            for (int i : sum)                list.add(i);            collection.add(list);        }        //如果sum不满足或者已经记录,则k++,即给sum重新安排数字        if (++k > sum.length)            break;        //将end和n分别更新        end = sum[k - 1];        n += end--;    }    return collection;}
0 0
原创粉丝点击