leetcode40(组合总和II:回溯法)

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。

输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]

题解:这道题的解法与leetcode39(组合总和)基本上是一致的,只不过会多一个去重步骤,比如对于数组[2,2,3]和target:5,如果按照正常的回溯法,使用与leetcode39(组合总和)一样的解法会得到两个重复的答案[2,3]和[2,3],我们需要在回溯的过程中进行去重,最有效的去重方法是构造一个List容器,存储数组中出现的元素和该元素出现的次数,我们递归时不再递归原数组,而是构造的List容器,一个元素出现次数为n次,说明该元素可以被递归0到n次,也就是在一个解集数组中可以出现0到n次,我们只需要利用回溯枚举这0到n次,就可以得到所有结果,并且达到去重的目的

class Solution {
    
    
    private  final Stack<Integer>stack=new Stack<>();
    private  final List<List<Integer>>res=new ArrayList<>();
    private  final List<int[]>arrayElements=new LinkedList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
    
    
        Solution.sort(candidates);
        int repeat=1;
        //构造List容器,存储数组中的元素及其出现次数
        for(int i=0;i< candidates.length-1;i++){
    
    
            if(candidates[i]==candidates[i+1])
                repeat++;
            else{
    
    
                 arrayElements.add(new int[]{
    
    candidates[i],repeat});
                repeat=1;
            }
        }
        arrayElements.add(new int[]{
    
    candidates[candidates.length-1],repeat});
        backTrace(candidates,0,0,target);
        return res;
    }
    private void backTrace(int[]candidates,int pos,int sum,int target){
    
    
          if(sum==target)
              res.add(new ArrayList<>(stack));
          if(pos>=arrayElements.size())
              return;
          int element=arrayElements.get(pos)[0];
          int repeat=arrayElements.get(pos)[1];
          if(target-sum<element)
              return;
          //执行一次循环,则解集数组中出现一次该元素
          for(int i=0;i<repeat;i++){
    
    
              stack.push(element);
              backTrace(candidates,pos+1,sum+element*(i+1),target);
          }
          for(int i=0;i<repeat;i++){
    
    
              stack.pop();
          }
          //结果数组中没有该元素
          backTrace(candidates,pos+1,sum,target);

    }

    //快排算法
    public static void sort(int[]args){
    
    
        quickSort(args,0,args.length-1);
    }
    private static void quickSort(int[]args,int start,int end){
    
    
        if(start>=end)
            return;
        int pivot=args[start];
        int left=start;
        int right=end;
        while(left<right){
    
    
            while(args[right]>pivot&&left<right)
                right--;
            while(args[left]<=pivot&&left<right)
                left++;
            change(args,right,left);
        }
        change(args,start,left);
        quickSort(args,start,left-1);
        quickSort(args,left+1,end);
    }
    private static void change(int[]args,int x,int y){
    
    
        int temp=args[x];
        args[x]=args[y];
        args[y]=temp;
    }

  
}

猜你喜欢

转载自blog.csdn.net/CY2333333/article/details/108524877