介紹
LeetCode300題小目標達成
這是一類問題,都可以用backtrack(回溯法)來求,這裏放在一起比較一下異同。首先是Combination Sum I,問題:給定一個int數組,不包含重複數字,現在需要從裏面可重複地取出一些數使得它們的和爲target,返回所有不同的取法。這裏可以從兩個角度考慮:1.每次往arr裏面添加數據,比如添加1,那麼剩下的就是在數據集中找到和爲target-1的所有可能,並保存數據,如果最後的目標小於0,那麼返回,等於0則添加至list;2.同樣的每次添加數據,剩下的起點則從添加的數據開始,比如1,直到最終結果=target,則添加至list中。這裏爲了防止出現保存重複的結果,每次都從數組當前位置往後遍歷。(見代碼I中變量start)。
然後是Combination Sum II。和第一題不同的是,數組包含重複數字,但是不能重複取。方法大致不變,仍然是回溯法,但是這裏每次回溯的起始位置就需要變成start+1了。還有一點不同,這裏包含重複數據,爲了防止記錄重複的結果,這裏我們把數組先從小到大排序,並且用HashSet去除重複結果。代碼見下2。
最後是Combination Sum III。現在需要從1~9中選擇個不同的數字使得它們的和爲。這樣一來,限定了每個可能結果的長度,即是。不怕,我們在回溯中再添加一個變量,用於記錄當前結果的長度,或者直接用當前結果arr的長度來和目標比較,回溯的大致思路不變,只是每次回溯的判定和邊界條件發生變化。代碼見下3。
總結起來就是萬變不離其宗,我們想要求f(target),那麼我們就去嘗試先試着添加一個元素a,那麼剩下的結果就變成了求f(target-a),依次類推,直到最後爲0,這樣就算一次滿足條件的組合。
還有一道Combination Sum IV,不過這裏只要求滿足條件的個數,因此可以用DP來求解,代碼見下4。
Java代碼
Combination Sum I代碼:
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> list = new ArrayList();
dfs(list, new ArrayList<Integer>(), candidates,target,0,0);
return list;
}
public void dfs(List<List<Integer>> list, List<Integer> arr, int[] candidates, int target, int sum, int start){
if(sum >target) return;
if(sum==target){
list.add( new ArrayList<>(arr));
return;
}
else{
for(int i=start;i<candidates.length;i++){
arr.add(candidates[i]);
dfs(list,arr,candidates,target,sum+candidates[i],i);
arr.remove(arr.size()-1);
}
}
}
Combination Sum II:
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> list = new ArrayList();
Arrays.sort(candidates);
dfs(list, new ArrayList<Integer>(), candidates,target,0,0);
HashSet hs = new HashSet(list);
list.clear();
list.addAll(hs);
return list;
}
public void dfs(List<List<Integer>> list, List<Integer> arr, int[] candidates, int target, int sum, int start){
if(sum >target) return;
if(sum==target){
list.add( new ArrayList<>(arr));
return;
}
else{
for(int i=start;i<candidates.length;i++){
arr.add(candidates[i]);
dfs(list,arr,candidates,target,sum+candidates[i],i+1);
arr.remove(arr.size()-1);
}
}
}
Combination Sum III:
public List<List<Integer>> combinationSum3(int k, int n) {
List<List<Integer>> list = new ArrayList();
dfs(list, new ArrayList<Integer>(), n, 1, k);
return list;
}
public void dfs(List<List<Integer>> list, List<Integer> arr, int tar, int start, int num){
if(tar<0||arr.size()>num) return;
if(tar==0&&arr.size()==num){
list.add(new ArrayList<>(arr));
return;
}
else{
for(int i=start;i<=tar&&i<=9;i++){
arr.add(i);
dfs(list,arr,tar-i,i+1,num);
arr.remove(arr.size() - 1);
}
}
}
Combination Sum IV:
public int combinationSum4(int[] nums, int target) {
int dp[] = new int[target+1];
dp[0]=1;
for(int i=1;i<=target;i++){
for(int j=0;j<nums.length;j++){
if(i>=nums[j]) dp[i] += dp[i-nums[j]];
}
}
return dp[target];
}