原题 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。
示例 1:
1 2 3 4 5 6 输入:candidates = [2,3,6,7], target = 7 输出:[[2,2,3],[7]] 解释: 2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。 7 也是一个候选, 7 = 7 。 仅有这两种组合。
示例 2:
1 2 输入: candidates = [2,3,5], target = 8 输出: [[2,2,2,2],[2,3,3],[3,5]]
示例 3:
1 2 输入: candidates = [2], target = 1 输出: []
提示:
1 <= candidates.length <= 30
1 <= candidates[i] <= 200
candidate 中的每个元素都 互不相同
1 <= target <= 500
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/combination-sum 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析 基本不用想就知道要使用递归,同时通过进一步的思考会发现如果使用递归算法将会产生大量的冗余计算,首先进入我的想法的是带存储器的递归,通过hashMap来避免重复计算。重新仔细阅读题目,发现hashMap在这个环境中不能正常工作,因为往往针对一个target有多种解法并不是一对一的关系。
分析题目可以发现递归过程可以作为一棵树,而这棵树中重复的节点是由于在产生子节点的时候考虑了所有的侯选数,只要按顺序考虑候选数就可以在不重复的前提下保证计算到所有的情况,如图:
接下来就可以写出对应的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package algorithms;import java.util.ArrayDeque;import java.util.ArrayList;import java.util.Deque;import java.util.List;public class question39 { static class Solution { public List<List<Integer>> combinationSum(int [] candidates, int target) { List<List<Integer>> res = new ArrayList<>(); if (candidates.length == 0 ) return res; Deque<Integer> tempRes = new ArrayDeque<>(); dfs(candidates, target, 0 , tempRes, res); return res; } public void dfs (int [] candidates, int target, int start, Deque<Integer> tempRes, List<List<Integer>> res) { if (target < 0 ) return ; if (target == 0 ) { res.add(new ArrayList<>(tempRes)); return ; } for (int i = start; i < candidates.length; i++) { tempRes.addLast(candidates[i]); dfs(candidates,target-candidates[i],i,tempRes,res); tempRes.removeLast(); } } } }
优化 有了上面的代码这道题其实已经解决,但是上面的代码尚有优化空间,若candidates能够有序排列就可以做到在前一项加和已经过大时中断枚举过程省去后续的计算步骤。
代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package algorithms;import java.util.*;public class question39 { static class Solution { public List<List<Integer>> combinationSum(int [] candidates, int target) { List<List<Integer>> res = new ArrayList<>(); if (candidates.length == 0 ) return res; Deque<Integer> tempRes = new ArrayDeque<>(); Arrays.sort(candidates); dfs(candidates, target, 0 , tempRes, res); return res; } public void dfs (int [] candidates, int target, int start, Deque<Integer> tempRes, List<List<Integer>> res) { if (target < 0 ) return ; if (target == 0 ) { res.add(new ArrayList<>(tempRes)); return ; } if (target < candidates[start]) return ; for (int i = start; i < candidates.length; i++) { tempRes.addLast(candidates[i]); dfs(candidates,target-candidates[i],i,tempRes,res); tempRes.removeLast(); } } } }
变体 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package algorithms;import java.util.*;public class question39 { static class Solution { public List<List<Integer>> combinationSum(int [] candidates, int target) { List<List<Integer>> res = new ArrayList<>(); HashMap<List<Integer>,Integer> allRes = new HashMap<>(); if (candidates.length == 0 ) return res; Deque<Integer> tempRes = new ArrayDeque<>(); Arrays.sort(candidates); dfs(candidates, target, 0 , tempRes, allRes); res.addAll(allRes.keySet()); return res; } public void dfs (int [] candidates, int target, int start, Deque<Integer> tempRes, HashMap<List<Integer>,Integer> allRes) { if (target < 0 ) return ; if (target == 0 ) { List<Integer> temp = new ArrayList<>(tempRes); allRes.put(temp,allRes.getOrDefault(temp,0 ) + 1 ); return ; } if (candidates.length == start) return ; if (target < candidates[start]) return ; for (int i = start; i < candidates.length; i++) { tempRes.addLast(candidates[i]); dfs(candidates, target - candidates[i], i + 1 , tempRes, allRes); tempRes.removeLast(); } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 import java.util.ArrayDeque;import java.util.ArrayList;import java.util.Arrays;import java.util.Deque;import java.util.List;public class Solution { public List<List<Integer>> combinationSum2(int [] candidates, int target) { int len = candidates.length; List<List<Integer>> res = new ArrayList<>(); if (len == 0 ) { return res; } Arrays.sort(candidates); Deque<Integer> path = new ArrayDeque<>(len); dfs(candidates, len, 0 , target, path, res); return res; } private void dfs (int [] candidates, int len, int begin, int target, Deque<Integer> path, List<List<Integer>> res) { if (target == 0 ) { res.add(new ArrayList<>(path)); return ; } for (int i = begin; i < len; i++) { if (target - candidates[i] < 0 ) { break ; } if (i > begin && candidates[i] == candidates[i - 1 ]) { continue ; } path.addLast(candidates[i]); dfs(candidates, len, i + 1 , target - candidates[i], path, res); path.removeLast(); } } public static void main (String[] args) { int [] candidates = new int []{10 , 1 , 2 , 7 , 6 , 1 , 5 }; int target = 8 ; Solution solution = new Solution(); List<List<Integer>> res = solution.combinationSum2(candidates, target); System.out.println("输出 => " + res); } }