public List<List<Integer>> combinationSum(int[] candidates, int target) { List<List<Integer>> list = new ArrayList<>(); Arrays.sort(candidates); recursive(list, new ArrayList<>(), candidates, target, 0); return list; }
/** * * @param list * 总的输出 list * @param tempList * 存放的 list * @param nums * 数组 * @param remain * 剩余值 * @param index * 数组下标 */ private void recursive(List<List<Integer>> list, List<Integer> tempList, int[] nums, int remain, int index) {
if (remain < 0) // return 或者进行 add 操作后就开始执行弹出尾部元素 塞入下个元素 return; else if (remain == 0) list.add(new ArrayList<>(tempList)); // 这里需要注意不能直接 list.add(tempList),最终 tempList 所指向的对象是空的, // 所以需要 new 一个新对象,将值复制进去 else { for (int i = index; i < nums.length; i++) { tempList.add(nums[i]); // 挨个塞入 recursive(list, tempList, nums, remain - nums[i], i); // 由于元素可重复 所以是 i tempList.remove(tempList.size() - 1); // 挨个弹出 } } }
public List<List<Integer>> combinationSum2(int[] candidates, int target) { List<List<Integer>> list = new ArrayList<>(); Arrays.sort(candidates); recursive(list, new ArrayList<>(), candidates, target, 0); return list;
}
/** * DFS 添加每个满足条件的集合 * * @param list * 最终返回集合 * @param tempList * 每个满足条件的子集合 * @param candidates * 数组 * @param remain * 剩余值 * @param index * 数组下标 */ private void recursive(List<List<Integer>> list, List<Integer> tempList, int[] candidates, int remain, int index) { if (remain < 0) return; else if (remain == 0) list.add(new ArrayList<>(tempList)); else { for (int i = index; i < candidates.length; i++) { if (i > index && candidates[i] == candidates[i - 1]) // 说明两个值相等且之前一个值已经返回 continue; tempList.add(candidates[i]); recursive(list, tempList, candidates, remain - candidates[i], i + 1); // 规定数组中每个数字在每个组合中只能使用一次 tempList.remove(tempList.size() - 1); } } }
相比较上一题的代码,这次只是加了一个条件判断以及递归中元素下标加了一。
这里就要对数组先进行排序操作了,新增的条件判断也是为了优化代码执行速度。
Combination Sum III
再来看第三道变形,描述如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。