[leetcode]40. Combination Sum II

非常典型的回溯法的排列数问题
x数组还是存解的下标,但是初始化的方式和子集树不一样
和39题区分开来

class Solution {
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        int t=0;
        int sum=0;
        //先排序,这样方便后面去重
        Arrays.sort(candidates);

        //x保存解的路径。
        int []x=new int[candidates.length];
        
        //解初始化为顺序解
        for(int i=0;i<candidates.length;i++)
            x[i]=i;
        
        List<List<Integer>> res=new ArrayList<>();
       
        backtrack(t,candidates,target,sum,x,res);
        
       
        return res;

        
    }
    
    private void backtrack(int t,int[] candidates, int target,int sum,int[]x,List<List<Integer>> res){
        
        if(t==candidates.length)return;
        
        for(int i=t;i<candidates.length;i++){
            
            if(sum+candidates[i]<=target){
                
                //把x[i] x[t]交换的意思就是取x[t]=i;
                //我一开始总写x[t]=i;再交换。怪不得疯狂出错。
                Swap(x,i,t);
                sum+=candidates[i];
               
                
                if(sum==target){
                     
                    List<Integer> oneRes=new ArrayList<Integer>();
                   
                   //如果sum==target,说明从树根到这一层就是一个可行解了。故j小于等于t。
                    for(int j=0;j<=t;j++){
        
                            oneRes.add(candidates[x[j]]);
                      
                    }
                  
                    //这里是去重操作
                       int flag=1;
                       //因为原数组有重复,所以非递减的结果也可能会重复
                       if(res.contains(oneRes))flag=0;
                       for(int j=1;j<oneRes.size();j++){
                       //如果递减说明重复了,例如1,2,5和5,2,1
                           if((int)oneRes.get(j)<(int)oneRes.get(j-1))flag=0;
                       }

                    if(flag==1)

                    res.add(oneRes);
                    
                    
                   
                }
                
                backtrack(t+1,candidates,target,sum,x,res);
                
                //回溯
                sum-=candidates[i];
                Swap(x,i,t);
            }
        }
    }
    //java没有传地址这一说,所以只能把整个x数组都传过去,再交换才行。
    private void Swap(int []x,int a,int b){
        int temp;
        temp=x[a];
        x[a]=x[b];
        x[b]=temp;
    }
}

先存一下这个总结贴:

https://leetcode.com/problems/combination-sum/discuss/16502/A-general-approach-to-backtracking-questions-in-Java-(Subsets-Permutations-Combination-Sum-Palindrome-Partitioning)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值