[LeetCode]Combination Sum

来源:互联网 发布:java if switch 效率 编辑:程序博客网 时间:2024/05/06 20:35

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]
]


本题难度medium。

【注意】
本题允许重复抽取同一个数字。(The same repeated number may be chosen from C unlimited number of times.)

【思路】
我刚开始准备采用3sum的办法,利用双指针向中间查找。这个办法不是不能用,效率也高,但是它的缺点就是要分别对candidates含有1个、2个、2个以上情况,以及还要另外写一个函数针对结果只有1个元素的情况:

ie. input:[1 2 3] 2 output中的[2]就是1个元素

这个缺点的原因在于这个办法的要求是candidates的length > 2

所以采用深度优先搜索算法(DFS)。虽然效率未必高,但是代码简洁不会出错。DFS的思路是把解空间按照从小到大含有某个元素的方式进行划分,例如:

假设该题的解空间:[1 1 1 1] [1 1 2] [1 3] [4]划分为:含有1[1 1 1 1] [1 1 2] [1 3]含有4[4]

我首先深度优先搜索含1的所有解,然后当我在深度优先搜索2时,就不必再考虑含有1的情况。这就是28行含有index的原因:

for(int i=index;i<size;i++)

【提示】
如果不好理解,就从树的角度来理解DFS。

DFS

【复杂度】
时间 O(N!) 空间 O(N) 递归栈空间

【注意】
1、candidates可能没有排过序
2、要越过重复的元素(第29行),否则就会出现重复的结果。(不过不加也不影响AC,估计是测试用例中没有重复元素的用例)例如:

input[1 1 1 1 1] 3
if(i!=index&&c[i-1]==c[i])   continue;

【代码】

public class Solution {    public List<List<Integer>> combinationSum(int[] candidates, int target) {        //require        List<List<Integer>> ans=new ArrayList<>();        if(candidates==null){            return ans;        }        int size=candidates.length;        if(size<1)            return ans;        //sort        Arrays.sort(candidates);        //invariant        List<Integer> preList=new ArrayList<Integer>();        helper(preList,0,candidates,target,ans);        //ensure        return ans;    }    public void helper(List<Integer> list,int index,int[] c,int target,List<List<Integer>> ans){        if(target<0)            return;        if(target==0){            List<Integer> oneComb= new ArrayList<Integer>(list);            ans.add(oneComb);        }else if(target>0){            int size=c.length;            for(int i=index;i<size;i++){                list.add(c[i]);                helper(list,i,c,target-c[i],ans);                list.remove(list.size()-1);            }        }    }}

【follow up】
我曾想通过采用“DFS+二分查找法”提高效率,将上面的代码改为:先利用二分查找法看看本级有没有element等于target,然后再向下级遍历。实际上这样会造成结果出现duplicates。因为DFS本身就可以搜索到所有解,所以必然会出现duplicates。

 同时,要注意DFS本身是末端节点处理,当处在中间的节点时并不进行处理。

参考

[Leetcode] Combination Sum 组合数之和

0 0
原创粉丝点击