Leetcode --- Combination Sum II
===
## Description
Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sum to target.
**Each number in candidates may only be used once in the combination.**
Note: The solution set must **not contain duplicate** combinations.
Input Array中的element可能會有重複,但每個element只能被用一次,而相同數列不同排列順序必須剃除在答案之外.
### Examples
* Ex1:
**Input:** candidates = [10,1,2,7,6,1,5], target = 8
**Output**
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
* Ex2:
**Input:** candidates = [2,5,2,1,2], target = 5
**Output:**
[
[1,2,2],
[5]
]
### Constarints
* 1 <= candidates.length <= 100
* 1 <= candidates[i] <= 50
* 1 <= target <= 30
## Solution
與Combination Sum I解題思路相同,透過DFS的想法,不過這次不允許自己被再次使用且重複的答案必須拿掉.
### Method 1:重複的使用function:array.indexOf()去檢查
```java=
class Solution {
public static int foo =0;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> ans = new ArrayList<>();
List<Integer> tmp = new ArrayList<>();
Arrays.sort(candidates);
DFS(0,target,0,candidates,ans,tmp);
return ans;
}
private void DFS(int start,int target,int sum,int[] candidates,List<List<Integer>> ans,List<Integer> tmp)
{
if(sum > target)
return;
else if(sum == target)
{
if(ans.indexOf(tmp) == -1)
ans.add(new ArrayList<Integer>(tmp));
return;
}
else
{
for(int i =start;i<candidates.length;i++)
{
sum +=candidates[i];
tmp.add(candidates[i]);
try
{
DFS(++start,target,sum,candidates,ans,tmp);
}
catch(Exception e)
{
DFS(start,target,sum,candidates,ans,tmp);
}
sum-= candidates[i];
tmp.remove(tmp.size()-1);
}
}
}
}
```
Line 6:必須先sort後面才能找到相同的數列去剃除
Line 28:使用try防止超出存取陣列範圍的Exception
Line 30:不存取自己所已++start
#### Submissions on Leetcode
Runtime: **929 ms, faster than 5.00%** of Java online submissions for Combination Sum II.
Memory Usage: **40 MB, less than 13.48%** of Java online submissions for Combination Sum II.
#### Complexity Analysis
Worse case:O(2^n^)
### Method 2:
優化速度,重複的就不進遞迴了且採用Backtracking,
為什麼倒著找會比順著找還快呢?我猜是因為我們的Array排列成ascending order,下面給出descending order的範例
* Ascending order且backtracking:
```java=
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> ans = new ArrayList<>();
List<Integer> tmp = new ArrayList<>();
Arrays.sort(candidates);
DFS(0,target,candidates,ans,tmp);
return ans;
}
private void DFS(int start,int target,int[] candidates,List<List<Integer>> ans,List<Integer> tmp)
{
if(target <0)
return;
else if(target == 0)
{
ans.add(new ArrayList<>(tmp));
return;
}
else
{
for(int i= start;i<candidates.length;i++)
{
if(i > start && candidates[i] == candidates[i-1])
continue;
tmp.add(candidates[i]);
DFS(i+1,target -candidates[i],candidates,ans,tmp);
tmp.remove(tmp.size()-1);
}
}
}
}
```
Line 24:已我為中心往下探且下一個等於我則跳過
#### Submission on Leetcode
Runtime: **4 ms, faster than 65.98%** of Java online submissions for Combination Sum II.
Memory Usage: **39.2 MB, less than 53.77%** of Java online submissions for Combination Sum II.
**非常吃test data==,吐的好速度快,吐不好就很慢(3~10ms)**
* Descending order且順著找:
```java=
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> ans = new ArrayList<>();
List<Integer> tmp = new ArrayList<>();
Arrays.sort(candidates);
for(int i =0 ;i<candidates.length/2;i++)
{
candidates[i] ^= candidates[candidates.length-i-1];
candidates[candidates.length-i-1] ^= candidates[i];
candidates[i] ^= candidates[candidates.length-i-1];
}
DFS(0,target,0,candidates,ans,tmp);
return ans;
}
private void DFS(int start,int target,int sum,int[] candidates,List<List<Integer>> ans,List<Integer> tmp)
{
if(sum> target )
return;
else if(target == sum)
{
ans.add(new ArrayList<>(tmp));
return;
}
else
{
for(int i= start;i<candidates.length;i++)
{
if(i > start && candidates[i] == candidates[i-1])
continue;
tmp.add(candidates[i]);
DFS(i+1,target,sum+candidates[i],candidates,ans,tmp);
tmp.remove(tmp.size()-1);
}
}
}
}
```
Line 5~13:先升序排列後再轉成降序排列
#### Submission on Leetcode
Runtime:**2 ms, faster than 99.02%** of Java online submissions for Combination Sum II.
Memory Usage: **38.9 MB, less than 91.94%** of Java online submissions for Combination Sum II.
**非常吃test data==,吐的好速度快,吐不好就很慢(3~10ms)**
#### Complexity Analysis
Worse case:O(2^n^)
###### tags: `Leetcode` `Medium` `DFS`