leetcode 39题 组合总和——回溯算法

题目:leetcode39题 求组合总数

题目截图

自己写的代码

version1

class Solution {
    List<List<Integer>> res=new LinkedList();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        int sum=0;
        LinkedList<Integer> track=new LinkedList();
        backTrack(candidates,target,track,sum);
        return res;
    }
    public void backTrack(int[] candidates,int target,LinkedList<Integer> track,int sum){
        if(sum==target){
            res.add(new LinkedList(track));
            return;
        }
        for(int i=0;i<candidates.length;i++){
            sum+=candidates[i];
            track.add(candidates[i]);
            backTrack(candidates,target,track,sum);
            track.removeLast();
            sum-=candidates[i];
        }
    }
}

编译都没通过,报错,track.add(candidates[i]);处栈溢出。
之后知道:严格把条件限制为sum==target,而有些情况下,sum<target<(candidates[i]+sum)。即sum在没加上candidates数组中的某一个值时是没到给的目标值target的,但加上之后又大于。就是没有sum==target,就会一直加。最后栈溢出。

version2

class Solution {
    List<List<Integer>> res=new LinkedList();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        int sum=0;
        LinkedList<Integer> track=new LinkedList();
        backTrack(candidates,target,track,sum);
        return res;
    }
    public void backTrack(int[] candidates,int target,LinkedList<Integer> track,int sum){
        if(sum==target){
            res.add(new LinkedList(track));
            return;
        }
        for(int i=0;i<candidates.length;i++){
            if(sum<=target){
                sum+=candidates[i];
                track.add(candidates[i]);
                backTrack(candidates,target,track,sum);
                track.removeLast();
                sum-=candidates[i]; 
            }
        }
    }
}

通过案例23/170
原因:没有去掉相同的组合。如输入[2,3,6,7] 7,输出为
[[2,2,3],[2,3,2],[3,2,2],[7]],但预期输出为[[2,2,3],[7]]
存在的问题:如何去掉汉相同的元素。
出现这个问题的原因分析:遍历数组元素时,一开始的元素a往前找可以组合为目的值的元素b,假如,a+b=target,就结束了。然后遍历a的后一个元素,以此类推。到以b开始遍历时,b又往前找元素,此时就会找到a,又返回b+a=target,与前一种情况只是顺序不同。
解决方法:每次遍历时,当前值不要往它前面找其他元素,而只往后。
实施:尝试使用全局变量i控制,一旦满足sum==target就重新让i=0,行不通。

参考别人的解决方法

backTrack方法中加入变量starti起使于start,在回溯/回归算法中就能将上一次的值传到下一次。
代码

class Solution {
    List<List<Integer>> res=new LinkedList();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        // int sum=0;
        LinkedList<Integer> track=new LinkedList();
        backTrack(candidates,target,track,0,0);
        return res;
    }
    public void backTrack(int[] candidates,int target,LinkedList<Integer> track,int sum,int start){
        if(sum==target){
            res.add(new LinkedList(track));
            return;
        }
        for(int i=start;i<candidates.length;i++){
            if(sum<=target){
                sum+=candidates[i];
                track.add(candidates[i]);
                backTrack(candidates,target,track,sum,i);
                track.removeLast();
                sum-=candidates[i]; 
            }
        }
    }
}

代码中可以改进之处

在for循环中加入了if判断(而且是for中要执行的语句都放在了if语句中),目的是想要满足一定条件才执行。此时可以把if移出for循环
即代码改为如下:

class Solution {
    List<List<Integer>> res=new LinkedList();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        // int sum=0;
        LinkedList<Integer> track=new LinkedList();
        backTrack(candidates,target,track,0,0);
        return res;
    }
    public void backTrack(int[] candidates,int target,LinkedList<Integer> track,int sum,int start){
        if(sum==target){
            res.add(new LinkedList(track));
            return;
        }
        if(sum>target) return;
        for(int i=start;i<candidates.length;i++){ 
                sum+=candidates[i];
                track.add(candidates[i]);
                backTrack(candidates,target,track,sum,i);
                track.removeLast();
                sum-=candidates[i];  
        }
    }
}

可以减小运行时间

总结

如果想要将一个参数的值传到下一次调用,可以将这个参数放在方法的参数列表中。【一般使用于回溯/回归算法值中】

backTrack()
|  ……
| String str=”rqm“
| ……
|(回溯)
|______backTrack()

如图所示,想要在第二个的backTrack中使用第一个backTrack中改变了的参数值str,就可以将str作为backTrack的参数,从而可以在第二个backTrack中操作str

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值