LeetCode Combination Sum I,II,III,IV

介绍

LeetCode300题小目标达成
这是一类问题,都可以用backtrack(回溯法)来求,这里放在一起比较一下异同。首先是Combination Sum I,问题:给定一个int数组,不包含重复数字,现在需要从里面可重复地取出一些数使得它们的和为target,返回所有不同的取法。这里可以从两个角度考虑:1.每次往arr里面添加数据,比如添加1,那么剩下的就是在数据集中找到和为target-1的所有可能,并保存数据,如果最后的目标小于0,那么返回,等于0则添加至list;2.同样的每次添加数据,剩下的起点则从添加的数据开始,比如1,直到最终结果=target,则添加至list中。这里为了防止出现保存重复的结果,每次都从数组当前位置往后遍历。(见代码I中变量start)。

然后是Combination Sum II。和第一题不同的是,数组包含重复数字,但是不能重复取。方法大致不变,仍然是回溯法,但是这里每次回溯的起始位置就需要变成start+1了。还有一点不同,这里包含重复数据,为了防止记录重复的结果,这里我们把数组先从小到大排序,并且用HashSet去除重复结果。代码见下2。

最后是Combination Sum III。现在需要从1~9中选择kk个不同的数字使得它们的和为nn。这样一来,限定了每个可能结果的长度,即是kk。不怕,我们在回溯中再添加一个变量,用于记录当前结果的长度,或者直接用当前结果arr的长度来和目标kk比较,回溯的大致思路不变,只是每次回溯的判定和边界条件发生变化。代码见下3。

总结起来就是万变不离其宗,我们想要求f(target),那么我们就去尝试先试着添加一个元素a,那么剩下的结果就变成了求f(target-a),依次类推,直到最后为0,这样就算一次满足条件的组合。

还有一道Combination Sum IV,不过这里只要求满足条件的个数,因此可以用DP来求解,代码见下4。

Java代码

Combination Sum I代码:

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> list = new ArrayList();
        dfs(list, new ArrayList<Integer>(), candidates,target,0,0);
        return list;
    }
    public void dfs(List<List<Integer>> list, List<Integer> arr, int[] candidates, int target, int sum, int start){
        if(sum >target) return;
        if(sum==target){
            list.add( new ArrayList<>(arr));
            return;
        }
        else{
            for(int i=start;i<candidates.length;i++){
                arr.add(candidates[i]);
                dfs(list,arr,candidates,target,sum+candidates[i],i);
                arr.remove(arr.size()-1);
            }
        }
    }

Combination Sum II:

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> list = new ArrayList();
        Arrays.sort(candidates);
        dfs(list, new ArrayList<Integer>(), candidates,target,0,0);
        HashSet hs = new HashSet(list);
        list.clear();
        list.addAll(hs);
        return list;
    }
    public void dfs(List<List<Integer>> list, List<Integer> arr, int[] candidates, int target, int sum, int start){
        if(sum >target) return;
        if(sum==target){
            list.add( new ArrayList<>(arr));
            return;
        }
        else{
            for(int i=start;i<candidates.length;i++){
                arr.add(candidates[i]);
                dfs(list,arr,candidates,target,sum+candidates[i],i+1);
                arr.remove(arr.size()-1);
            }
        }
    }

Combination Sum III:

    public List<List<Integer>> combinationSum3(int k, int n) {
        List<List<Integer>> list = new ArrayList();
        dfs(list, new ArrayList<Integer>(), n, 1, k);
        return list;
    }
    public void dfs(List<List<Integer>> list, List<Integer> arr, int tar, int start, int num){
        if(tar<0||arr.size()>num) return;
        if(tar==0&&arr.size()==num){
            list.add(new ArrayList<>(arr));
            return;
        }
        else{
            for(int i=start;i<=tar&&i<=9;i++){
                arr.add(i);
                dfs(list,arr,tar-i,i+1,num);
                arr.remove(arr.size() - 1);
            }
        }
    }

Combination Sum IV:

    public int combinationSum4(int[] nums, int target) {
        int dp[] = new int[target+1];
        dp[0]=1;
        for(int i=1;i<=target;i++){
            for(int j=0;j<nums.length;j++){
                if(i>=nums[j]) dp[i] += dp[i-nums[j]];
            }
        }
        return dp[target];
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章