X Tutup
M 1531549407 tags: Array, DFS, Backtracking, Combination time: O(n!) space: O(n!) 给一串数字candidates (no duplicates), 和一个target. 找到所有unique的 组合(combination) int[], 要求每个combination的和 = target. 注意: 同一个candidate integer, 可以用任意多次. #### DFS, Backtracking - 考虑input: 没有duplicate, 不需要sort - 考虑重复使用的规则: 可以重复使用, 那么for loop里面dfs的时候, 使用curr index i - the result is trivial, save success list into result. ##### Time complexity for Combination (reuse-candidate) - at each level dfs, we have the index as starting point: - if we are at `index=0, we can have n child dfs() options via for loop`; - if at `index=1, we will have (n-1) dfs options via for loop`. - Consider it as the `pick/not-pick` problem, where the difference is you can pick `x` times at each index rather than only 2 times. - Overall, we will multiply the # of possibilities: n * (n - 1) * (n - 2) ... * 1 = n! => `O(n!)` ##### Combination DFS 思想 - 在每个index上面都要面临: `pick/not pick的选择`, 用for loop over index + backtracking 实现 picks. - 每次pick以后, 就生成一条新的routine, from this index - 下一个level的dfs从这个index开始, 对后面(或者当下/if allow index reuse) 进行同样的 pick/not pick 的选择 - 注意1: 每个level dfs 里面, for loop 里会有 end condition: 就不必要dfs下去了. - 注意2: Backtracking在success case && dfs case 后都要做, 因为backtrack 是为了之前上一层dfs. ``` /** Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target. The same repeated number may be chosen from candidates unlimited number of times. Note: All numbers (including target) will be positive integers. The solution set must not contain duplicate combinations. Example 1: Input: candidates = [2,3,6,7], target = 7, A solution set is: [ [7], [2,2,3] ] Example 2: Input: candidates = [2,3,5], target = 8, A solution set is: [ [2,2,2,2], [2,3,3], [3,5] ] */ /* - one item can be picked for multiple times: - use dfs, for loop to aggregate candidates - do target - val to track, and when target == 0, that’s a solution - dfs(curr index i), instead of (i + 1): allows reuse of item */ class Solution { public List> combinationSum(int[] candidates, int target) { List> result = new ArrayList<>(); if (validate(candidates, target)) return result; dfs(result, new ArrayList<>(), candidates, 0, target); return result; } // for loop, where dfs is performed private void dfs(List> result, List list, int[] candidates, int index, int target) { for (int i = index; i < candidates.length; i++) { int value = candidates[i]; list.add(value); if (target == value) result.add(new ArrayList<>(list)); // one closure else if (target - value > 0) dfs(result, list, candidates, i, target - value); list.remove(list.size() - 1); // backtrack } } private boolean validate(int[] candidates, int target) { return candidates == null || candidates.length == 0 || target <= 0; } } /* LintCode: Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. The same repeated number may be chosen from C unlimited number of times. For example, given candidate set 2,3,6,7 and target 7, A solution set is: [7] [2, 2, 3] Note All numbers (including target) will be positive integers. Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak). The solution set must not contain duplicate combinations. Example given candidate set 2,3,6,7 and target 7, A solution set is: [7] [2, 2, 3] Tags Expand Backtracking Array Thinking process: Similar to 'Combination' problem, do back-tracking with ability to repeat itself at index i. In order to stop duplicates of result entry, use a 'prev' tracker to 'continue' if a value is repeating at any index. Skip repeating integers because we've already allow unlimited # of same integer in one single solution. (IMPORTANT: will have to sort the int[] in order to detect the duplicates) In particular, I pass a 'sum' to compare with 'target' (want to have sum == target). Some solution prefer to use 'target - someVlaue' == 0 to find solution. */ /* Previous Note: Seems like LintCode makes the input containing duplicates: that's why it needs to sort. 递归,backtracking. 非常normal, 需要先sort. 记得求sum时候也pass 一个sum进去,backtracking一下sum也,这样就不必每次都sum the list了。 题目里面所同一个元素可以用n次,但是,同一种solution不能重复出现。如何handle? 1. 用一个index (我们这里用了start)来mark每次recursive的起始点。 2. 每个recursive都从for loop里面的i开始,而i = start。 也就是,下一个iteration,这个数字会有机会被重复使用。 3. 同时,确定在同一个for loop里面,不同的Index上面相同的数字,不Process两遍。用一个prev 作为checker. 假如[x1, x2, y, z], where x1 == x2, 上面做法的效果: 我们可能有这样的结果: x1,x1,x1,y,z 但是不会有:x1,x2,x2,y,z 两个solution从数字上是一样的,也就是duplicated solution, 要杜绝第二种。 */ public class Solution { /** * @param candidates: A list of integers * @param target:An integer * @return: A list of lists of integers */ public List> combinationSum(int[] num, int target) { List> rst = new ArrayList>(); List list = new ArrayList(); if (num == null || num.length == 0 || target < 0) { return rst; } Arrays.sort(num); helper(rst, list, num, target, 0, 0); return rst; } public void helper(List> rst, List list, int[] num, int target, int sum, int start) { if (sum == target) { rst.add(new ArrayList(list)); return; } else if (sum > target) {//Stop if greater than target return; } int prev = -1;//Repeat detection for (int i = start; i < num.length; i++) { if (prev != -1 && prev == num[i]) { continue; } list.add(num[i]); sum += num[i]; helper(rst, list, num, target, sum, i); //Back track: sum -= num[i]; list.remove(list.size() - 1); //Repeat Detection prev = num[i]; } } } ```
X Tutup