image.png

解决思路

回溯算法 + 剪枝

image.png
image.png
image.png

code

  1. public List<List<Integer>> combinationSum2(int[] candidates, int target) {
  2. int len = candidates.length;
  3. List<List<Integer>> res = new ArrayList<>();
  4. if (len == 0) {
  5. return res;
  6. }
  7. // 先将数组排序,这一步很关键
  8. Arrays.sort(candidates);
  9. Deque<Integer> path = new ArrayDeque<>(len);
  10. dfs(candidates,len,0,target,path,res);
  11. return res;
  12. }
  13. /**
  14. * @param candidates 候选数组
  15. * @param len
  16. * @param begin 从候选数组的 begin 位置开始搜索
  17. * @param residue 表示剩余,这个值一开始等于 target,基于题目中说明的"所有数字(包括目标数)都是正整数"这个条件
  18. * @param path 从根结点到叶子结点的路径
  19. * @param res
  20. */
  21. private void dfs(int[] candidates,int len,int begin,int residue,Deque<Integer> path, List<List<Integer>> res){
  22. if (residue == 0) {
  23. res.add(new ArrayList<>(path));
  24. return;
  25. }
  26. for (int i = begin;i < len;i++){
  27. // 大剪枝
  28. if (residue - candidates[i] < 0)
  29. break;
  30. // 小剪枝
  31. if (i > begin && candidates[i] == candidates[i - 1])
  32. continue;
  33. path.addLast(candidates[i]);
  34. // 因为元素不可以重复使用,这里递归传递下去的是 i + 1 而不是 i
  35. dfs(candidates,len,i+1,residue - candidates[i],path,res);
  36. path.removeLast();
  37. }
  38. };