原题链接:https://leetcode-cn.com/problems/combination-sum-ii
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
这个题目与上一个题目基本相似,只是不能重复使用税数字了。所以根据上一题的代码,尝试修改,将起点位置修改为i+1。尝试执行。
public List<List<Integer>> combinationSum(int[] candidates, int target) { List<List<Integer>> result = new ArrayList<List<Integer>>(); List<Integer> daan = new ArrayList<>(); backtrack(result,candidates,target,daan,0,0); return result; } //回溯算法 public void backtrack(List<List<Integer>> result,int[] candidates, int target,List<Integer> daan,int sum ,int start ){ if(sum == target){ result.add(new ArrayList<Integer>(daan)); return; } if(sum>target){ return; } for(int i=start;i<candidates.length;i++){ if(sum+candidates[i]<=target){ daan.add(candidates[i]); backtrack(result,candidates,target,daan,sum+candidates[i],i+1); daan.remove(daan.size()-1); } } }
执行之后,发现当给定数组中有重复数字的时候可能会出现重复结果,所以思考如何去重。
我使用了一个set 集合,将符合条件的结果进行排序之后,和set集合内的进行比较,如果有则跳过,没有则放到结果集,和set集合中。
代码如下:
public List<List<Integer>> combinationSum2(int[] candidates, int target) { List<List<Integer>> result = new ArrayList<List<Integer>>(); List<Integer> daan = new ArrayList<>(); Set<ArrayList<Integer>> chongfu= new HashSet<>(); backtrack(result,candidates,target,daan,0,0,chongfu); return result; } //回溯算法 public void backtrack(List<List<Integer>> result, int[] candidates, int target, List<Integer> daan, int sum , int start , Set<ArrayList<Integer>> chaongfu){ if(sum == target){
//这部分为去重的内容。 List<Integer> ans=new ArrayList<Integer>(daan); //不能直接使用daan ,因为这样修改的其中顺序,下边的结果将会出错。 Collections.sort(ans); if(!chaongfu.contains(ans)){ result.add(new ArrayList<Integer>(ans)); chaongfu.add(new ArrayList<Integer>(ans)); } return; } if(sum>target){ return; } for(int i=start;i<candidates.length;i++){ if(sum+candidates[i]<=target){ daan.add(candidates[i]); backtrack(result,candidates,target,daan,sum+candidates[i],i+1,chaongfu); daan.remove(daan.size()-1); } }