LeetCode組合總和I IV和揹包問題小結

2022-02-20 22:41:14 字數 3367 閱讀 9922

組合總和ii

組合總和iii

組合總和iv

對比如下,為了便於對比,將原題目的敘述方式進行了修改。

問題輸入

取值限定

解集限定解法i

無重複元素的陣列 candidates且全為正數;目標數 target

candidates元素可以無限制重複被選取

無重複集合

回溯法,對每乙個候選值可以選0~n次,滿足已選之數總和小於等於target。輸入無重複+回溯本身保證結果集無重複

ii可能有重複元素的陣列 candidates且全為正數;目標數 target

candidates元素只能選一次

無重複集合

建立candidates元素與其個數的hashmap,基於選擇個數做回溯法

iiicandidates=[1,2,...,9],目標數 target,個數k

candidates元素只能選一次,只能選k個

無重複集合

回溯法,按順序遍歷每個元素分別考慮選與不選。其他解法見原鏈結

iv無重複元素的陣列 candidates且全為正數;目標數 target

candidates元素可以無限制重複被選取

無重複陣列(順序不同認為是不同解)

轉換為揹包問題的動態規劃解法。先排序再用回溯法求所有無重複集合的解,最後構造結果的解法會超時。

分類輸入

取值限定

解法0-1揹包

揹包容量v,n種物品其體積w[1...n]和價值v[1...n]

每個物品最多取1次

見狀態轉移方程

完全揹包

揹包容量v,n種物品其體積w[1...n]和價值v[1...n]

每個物品可以取無限次

見狀態轉移方程

多重揹包

揹包容量v,n種物品其體積w[1...n]和價值v[1...n],個數分別為k[1...n]

第i個物品可以取0至k[i]次

見狀態轉移方程

0-1揹包

優化:觀察狀態轉移方程時可以發現,每次都直接使用i-1行的結果來構造第i行的結果,那麼只需要儲存一行即可。且在遍歷時,必須使用倒序遍歷j->1防止本輪的變化覆蓋到上一輪的結果上去,導致這一變化被再次取出來。

儲存當前行的最大值,那麼這個最大值在求解最後一行時即為所求的結果。

去掉i這乙個維度可改寫為:

完全揹包

在0-1揹包基礎上,因為每件可以使用無限次(實際上有乙個上界——不超過當前剩餘容量)。公式為:

但是結合0-1揹包優化的過程:j倒序遍歷是為了避免重複取第i個元素造成重複更新。那麼反過來利用這個特性,正好能表達每個元素取無限個的特點。

那麼優化公式為:

for (int i = 0; i <= v; i++) dp[i] = 0;//初始化二維陣列

//迴圈每個物品

for (int i = 1; i <= n; i++)

}

可以看出去掉了原始公式中k的這一層迴圈,並且將j的下界進行了優化,減少了判斷語句。

多重揹包

可以將所有型別的物品看做不同種類的,轉化為0-1揹包。

也可以沿著原先完全揹包的思路,dp[i][j] = max(dp[i-1][j-k*w[i]] + k*v[i]),其中k=0,1, 2...k[i]取整。

這兩種時間複雜度都是o(n^3)的。

有一種優化的方法是按2的冪將k件第i種物品拆分,如20=1+2+4+8+5,再使用0-1揹包,可以降低至o(n^2logn)

還有更多的優化方法,可以參考 **多重揹包的一些解法

上文所討論的三種揹包問題基本場景,都是基於求結果的組合數的,即不考慮結果中元素的順序,對於v=4,[1, 3]和[3, 1]是同乙個解。

如果要求排列數,又如何解呢?

從上文的討論過程可以發現,如果先按照順序取n個/種物品再遍歷揹包容量v,解中第i個總在第i+1個前面,沒有考慮順序。如果先遍歷容量v,再遍歷元素,自然就形成了排序的解。還以v=4舉例,取i=1時,v-i=3;取i=3時,v-i=1,此時可以得出出[1, 3]和[3, 1]兩個不同的解。

因此,第一版的狀態轉移方程為:

for(int i=0;i<=target;i++) 

int dp = new int[target+1];

for(int j=0;j= 0)

}return dp[target];

}}

494. 目標和

可以看做元素是取正還是取反的揹包問題。注意這一題進行座標平移(+1000)和使用遞推式替代狀態轉移方程,複雜度會更低。後者即

將 dp[i][j] = dp[i - 1][j - nums[i]] + dp[i - 1][j + nums[i]] 改寫為

518.零錢兌換 ii

典型的完全揹包問題,典型的優化方式。

class solution 

if(amount<0)

if(coins == null || coins.length == 0)

int dp = new int[amount+1];

dp[0] = 1;

for(int i=0;i416. 分割等和子集

0-1揹包。變化點是求固定的dp[v]是否存在(true or false)。

class solution

int sum = 0;

for(int i=0;i>1;

// 0-1揹包

// 第i個數字, 和為j

boolean dp = new boolean[half+1];

dp[0] = true;

for(int i=0;i=0;j--)

if(j==half && dp[j]) }}

return false;

}}

139. 單詞拆分

直接套用參考文件希望用一種規律搞定揹包問題

中true-false * 完全揹包 問題的公式:

class solution

if(worddict == null ||worddict.size() ==0)

boolean dp = new boolean[s.length()+1];

dp[0] = true;

for(int i=0;i<=s.length();i++)

if(amount<0 || coins==null || coins.length == 0)

int dp = new int[amount+1];

dp[0] = 0;

for(int i=1;i<=amount;i++)

for(int i=0;i希望用一種規律搞定揹包問題

【演算法總結】動態規劃-揹包問題

LeetCode 組合總和

給定乙個由正整數組成且不存在重複數字的陣列,找出和為給定目標正整數的組合的個數。示例 nums 1,2,3 target 4 所有可能的組合為 1,1,1,1 1,1,2 1,2,1 1,3 2,1,1 2,2 3,1 請注意,順序不同的序列被視作不同的組合。因此輸出為 7。高階 如果給定的陣列中含...

LeetCode組合總和

39.給定乙個無重複元素的陣列 candidates 和乙個目標數 target 找出 candidates 中所有可以使數字和為 target 的組合。candidates 中的數字可以無限制重複被選取。說明 所有數字 包括 target 都是正整數。解集不能包含重複的組合。解法 static l...

LeetCode 組合總和

部落格說明 介紹39.組合總和 題目給定乙個無重複元素的陣列 candidates 和乙個目標數 target 找出 candidates 中所有可以使數字和為 target 的組合。candidates 中的數字可以無限制重複被選取。說明 所有數字 包括 target 都是正整數。解集不能包含重複...