一和零!!
本題考察的不是多重背包
多重背包是每個物品,數量不同的情況。
本題中strs 數組里的元素就是物品,每個物品只有一個!
而m 和 n相當于是一個兩個維度的背包。
所以本題其實是01背包問題!
這不過這個背包有兩個維度,一個是m 一個是n,而不同長度的字符串就是不同大小的待裝物品。
開始動規五部曲:
確定dp數組(dp table)以及下標的含義
dp[i][j]:最多有 i 個 0 和 j 個 1 的 strs 的最大子集的大小為 dp[ i ][ j ]。
或者可以理解為一個最多裝 i 個 0 和 j 個 1 的背包最多裝幾個這樣的物品。
確定遞推公式
dp[i][j] 可以由前一個strs里的字符串推導出來,strs里的字符串有zeroNum個0,oneNum個1。
dp[i][j] 就可以是 dp[i - zeroNum][j - oneNum] + 1。
然后我們在遍歷的過程中,取dp[i][j]的最大值。
所以遞推公式:dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
回想一下01背包的遞推公式:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
對比一下就會發現,字符串的zeroNum和oneNum相當于物品的重量(weight[i]),字符串本身的個數相當于物品的價值(value[i])。
這就是一個典型的01背包! 只不過物品的重量有了兩個維度而已。
dp數組如何初始化
01背包的dp數組初始化為0就可以。
因為物品價值不會是負數,初始為0,保證遞推的時候dp[i][j]不會被初始值覆蓋。
確定遍歷順序
外層for循環遍歷物品,內層for循環遍歷背包容量且從后向前遍歷!
那么本題也是,物品就是strs里的字符串,背包容量就是題目描述中的m和n。
for (string str : strs) { // 遍歷物品int oneNum = 0, zeroNum = 0;for (char c : str) {if (c == '0') zeroNum++;else oneNum++;}for (int i = m; i >= zeroNum; i--) { // 遍歷背包容量且從后向前遍歷!for (int j = n; j >= oneNum; j--) {dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);}} }舉例推導dp數組
以輸入:[“10”,“0001”,“111001”,“1”,“0”],m = 3,n = 3為例
最后dp數組的狀態如下所示:
可以理解為一個物品有兩種重量不同的物質組成,一個是物質1,一個是物質2。而放物品的包也有兩個不同的兜用來分別裝某物品的物質1和物質2
總結