回溯法求解SubSet,Permutation,Combination Sum

简要介绍:
回溯法可以系统的搜索一个问题的所有解或任意解,在问题的解空间树中,按照深度优先搜索的策略,从根节点出发搜索解空间树。开始节点为活节点,同时也是当前的扩展节点。在当前的扩展节点处向纵深方向移动,此时这个节点为新的活节点。如果在当前的扩展节点处不能向纵深方向移动,那么此节点为死节点,此时,节点应往回移动,移动至最近的活节点处。

以下的三个问题都是用回溯的方法来解决的,其算法的框架基本相同。回溯法常用来解决的问题有子集问题和排列树问题,这两个问题在以下解答中均有提及。

问题1:
描述:给定一个整型数组,其中的整数均不相同,返回其所有的子集。结果中不能含有重复的子集。例如:
Input: nums = [1,2,3]
Output:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
解法:

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> list=new ArrayList<>();
        Arrays.sort(nums);
        backtrack(list,new ArrayList<>(),nums,0);
        return list;
    }
    
    public void backtrack(List<List<Integer>> l,ArrayList<Integer> al,int[] nums,int start){
        l.add(new ArrayList<>(al));
        for(int i=start;i<nums.length;i++){
            al.add(nums[i]);
            backtrack(l,al,nums,i+1);
            al.remove(al.size()-1);
        }
    }
}

问题2:
描述:组合问题。给定一个整型数组,其中的整数均不相同,返回所有不同的组合。例如:
Input: [1,2,3]
Output:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
解法:

class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> l=new ArrayList<>();
        backtrack(nums,l,new ArrayList<Integer>());
        return l;
    }
    public void backtrack(int[] nums,List<List<Integer>> l,List<Integer> al){
        if(al.size()==nums.length){
            l.add(new ArrayList<Integer>(al));
        }else{
            for(int i=0;i<nums.length;i++){
                if(al.contains(nums[i])){
                    continue;
                }
                al.add(nums[i]);
                backtrack(nums,l,al);
                al.remove(al.size()-1);
            }
        }    
    }
}

问题三
描述:给定一个整型数组和目标整数,求出数组中数的组合(数组中的数可以重复使用),使得这些数之和为目标数。例如:
Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
[7],
[2,2,3]
]
解法:

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> l=new ArrayList<>();
        backtrack(l,new ArrayList<Integer>(),candidates,target,0);
        return l;
    }
    
    public void backtrack(List<List<Integer>> l,List<Integer> al,int[] cand,int target,int start){
        
        if(sum(al)==target){
            l.add(new ArrayList<>(al));
        }
        for(int i=start;i<cand.length;i++){
            if(sum(al)+cand[i]>target){
                continue;
            }
            al.add(cand[i]);
            backtrack(l,al,cand,target,i);
            al.remove(al.size()-1);
        }
    }
    public int sum(List<Integer> al){
        int sum=0;
        for(int i=0;i<al.size();i++){
            sum+=al.get(i);
        }
        return sum;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值