39. Combination Sum

来源:互联网 发布:阿里云os5.1系统root 编辑:程序博客网 时间:2024/04/30 20:49

QUESTION

Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

The same repeated number may be chosen from C unlimited number of times.

Note
- All numbers (including target) will be positive integers.
- The solution set must not contain duplicate combinations.

For example, given candidate set [2, 3, 6, 7] and target 7,

A solution set is:

[  [7],  [2, 2, 3]]
THOUGHTS

这道题完完全全是自己做出来的,略开心啊。不过还是调试了几次,利用的是回溯法加上dfs,这种做法应该很熟悉了,上课看书是理解不了的,只有多做题才能熟练掌握,不是提倡题海战术,只不过要多做题多思考多总结。给出一列数组,还有一个目标值,求所有和为目标值的集合。其实dfs就是一棵树啊,回溯只不过是借助这种结构进行剪枝。

CODE
public class Solution {    public List<List<Integer>> combinationSum(int[] candidates, int target) {        List<List<Integer>> res = new ArrayList<List<Integer>>();        if(candidates == null || candidates.length == 0)            return res;        List<Integer> temp = new ArrayList<Integer>();        Arrays.sort(candidates);        dfs(candidates,target,res,temp,0,0);        return res;    }    public void dfs(int[] nums,int target,List<List<Integer>> res,List<Integer> temp,int sum,int start){        if(sum == target){            sum = 0;            res.add(new ArrayList<Integer>(temp));            return;        }        else if(sum > target){            sum = 0;            return;        }        for(int i = start;i < nums.length;i++){            temp.add(nums[i]);            sum += nums[i];            dfs(nums,target,res,temp,sum,i);            sum -= nums[i];            temp.remove(temp.size() - 1);            while(i < nums.length - 1 && nums[i] == nums[i + 1])                i++;        }    }}
RESULT

runtime complexity is O(n^2),space complexity is O(1).

#

SPECIAL ATTENTION
  • 在进行处理之前要先排序,因为可能会出现[3,2,2]的情况,答案给出的是[2,2,3]。
  • 排序之后,也要考虑结果重复的情况,比如candidates[] = {2,2,3},target = 5;那么处出现[2,3],[2,3]俩个结果,最好是在处理的时候跳过这种情况。方法就是如果下一个处理数和本次处理数相同,则跳过。
  • 还要考虑出现的一种情况是,结果中包含[2,2,3],[2,3,2],[3,2,2]为什么我们从小到大排序了还会出现这种情况呢?这是因为我们进行下次递归的时候不是从本节点以后开始的,而是又从0开始的,解决方法是,设置一个参数start,下次进行递归的时候从start开始,如果不允许结果重复,那么就从start + 1开始递归。很尴尬下道题就是这么出的,所以秒解。还需要注意的一点是当开始递归的时候,传递的参数不是start而是变成了i;

二刷

时间复杂度还是不会算,网上看到大神的答案也没看懂。
接下来就是复杂度分析。这道题的复杂度分析起来比较复杂….一刷的时候就没有好好思考。

首先我们假设这个数组candidate长为n, 在其中有m个元素小于target,假设T(n) = find(target),那么我们可以根据程序得到以下分析结果:

DFS Level 0: 我们首次调用辅助函数, 这一层的count = 1
DFS Level 1: 这时候我们进入了辅助函数的for循环,在for循环里我们有一个pruning,当candidate[i] > target的时候,返回,所以这一层我们只对小于target的元素进行下一层DFS,如我们假设的,结果为m
DFS Level 2: 根据代码,我们上一层有一个target -= num,所以这一层的target其实都不一样。
假设我们对candidate中最小的元素min进行分析,这时候新的target1 = target - min,此时我们要继续计算在candidate数组中有多少元素小于新的target1,假设这个数目为m1,则在这一层我们要对小于target1的m1个数组进行下一层的DFS
假如我们考虑其他非min的元素来计算总的复杂度时, 这时候两层总共要进行1 + m(m1 + m2 + m3 + … + mn)次调用。
由于每一层的target和m都在改变,以我的水平比较难计算出一个漂亮的公式,那么我就想办法简化一下:
这里递归的最大深度是d= target / min, 就是最深我们可以到 target / min这么多层DFS
Branching factor b = m, m是candidate数组里小于等于target的distinct元素的个数。 其实这里多算了,每一层的m都在减少,而且是不规则减少
我们利用DFS公式可以算出这里的Time Complexty = O(md), Space Complexity = O(m)
这只是一个worst case scenario, 更精确的计算还需要再花时间。

这是大神的csdn

二刷CODE

public class Solution {    public List<List<Integer>> combinationSum(int[] candidates, int target) {        List<List<Integer>> result = new ArrayList<List<Integer>>();        Arrays.sort(candidates);        List<Integer> temp = new ArrayList<Integer>();        if(candidates == null || candidates.length == 0)            return result;        sumHelper(result,temp,candidates,target,0);        return result;    }    public void sumHelper(List<List<Integer>> res,List<Integer> temp,int[] nums,int target,int index){        if(target == 0){            res.add(new ArrayList(temp));            return;        }        if(target < 0)        //这里之所以是return不是continue是因为数组是经过排序的        //如果当前的元素大于目标数,就没有必要再继续了,后面的肯定也大于            return;        for(int i = index;i < nums.length;i++){            if(nums[i] > target)                return;            //注意这里是i大于index            if(i > index && nums[i] == nums[i - 1])                continue;            temp.add(nums[i]);            target -= nums[i];            sumHelper(res,temp,nums,target,i);            temp.remove(temp.size() - 1);            target += nums[i];        }    }}
0 0