leetcode筆記 揹包問題總結1

2021-09-24 11:02:50 字數 2958 閱讀 3039

這部分內容是參考大神cyc2018的**和總結,將leetcode中和揹包問題相關的放在這裡。

1.字串按單詞列表分割

139. word break (medium)

這個問題也可以使用揹包問題的思路,把這個**放在問題139中了。

2.劃分陣列為相等的兩部分

416. partition equal subset sum (medium)

題目:給定乙個只包含正整數的非空陣列。是否可以將這個陣列分割成兩個子集,使得兩個子集的元素和相等。

注意:每個陣列中的元素不會超過 100

陣列的大小不會超過 200

示例 1:

輸入: [1, 5, 11, 5]

輸出: true

解釋: 陣列可以分割成 [1, 5, 5] 和 [11].

示例 2:

輸入: [1, 2, 3, 5]

輸出: false

解釋: 陣列不能分割成兩個元素和相等的子集.

思路:這個題可以看成是乙個0-1揹包問題。其中物品的總個數為陣列的長度,每個元素的值為物品的質量,我們可以先求出整個陣列的和sum,sum/2可以看成是揹包的容量。使用乙個一維的布林陣列dp,dp[i]表示和i能否被陣列中的元素表示。這種思路可以解決問題,但並不是最佳的解決方案,速度並不是最快的。

我自己寫**的時候,總是忘記給dp[0]賦初值,並且在寫內層j的迴圈時,總是出錯。。。要注意。for(int j=sum/2;j>=nums[i-1];j--)裡面是num[i-1],否則會出現陣列越界的錯誤

**:class solution

}return dp[sum/2];}}

3.改變一組數的正負號使得它們的和為一給定數

494. target sum (medium)

題目:給定乙個非負整數陣列,a1, a2, ..., an, 和乙個目標數,s。現在你有兩個符號 + 和 -。對於陣列中的任意乙個整數,你都可以從 + 或 -中選擇乙個符號新增在前面。

返回可以使最終陣列和為目標數 s 的所有新增符號的方法數。

示例 1:

輸入: nums: [1, 1, 1, 1, 1], s: 3

輸出: 5

解釋:-1+1+1+1+1 = 3

+1-1+1+1+1 = 3

+1+1-1+1+1 = 3

+1+1+1-1+1 = 3

+1+1+1+1-1 = 3

一共有5種方法讓最終目標和為3。

注意:陣列的長度不會超過20,並且陣列中的值全為正數。

初始的陣列的和不會超過1000。

保證返回的最終結果為32位整數。

思路:子集和問題

給乙個整數集合,問是否存在某個非空子集,使得子集內中的數字和為0

乙個等價的問題是:給乙個整數集合和另乙個整數s,問是否存在某個非空子集,使得子集中的數字和為s。子集合加總問題可以想成是揹包問題的乙個特例。

這部分是需要乙個數學的推導,我們可以將整個陣列劃分為兩個部分,一部分是符號為正的p,一部分是符號為負的n,兩者的和分別為,sum(p),sum(n).由題目可以滿足情況s=sum(p)-sum(n).此時在等式的兩邊同時加上sum(p),sum(n),可以得到下面的式子:

s+sum(p)+sum(n)=sum(p)+sum(n)+sum(p)-sum(n)

即sum(p)=[s+sum(p+n)]/2

即整個問題轉化成了我們需要在陣列中找出乙個子陣列,使得這個子陣列的和為[s+sum(p+n)]/2,可以看做是乙個0-1揹包問題。設定陣列dp[i],表示和為i的情況下有多少種方法。

但是我不太懂問什麼dp[0]=1?

我自己寫**的時候碰見的問題是沒有注意到特殊的情況,即s的值比整個陣列的和還要大,除此之外還有sum+s是個奇數,不能整除。

**:class solution

}return dp[w];}}

4.01字元構成最多的字串

474. ones and zeroes (medium)

題目:在計算機界中,我們總是追求用有限的資源獲取最大的收益。

現在,假設你分別支配著 m 個 0 和 n 個 1。另外,還有乙個僅包含 0 和 1 字串的陣列。

你的任務是使用給定的 m 個 0 和 n 個 1 ,找到能拼出存在於陣列中的字串的最大數量。每個 0 和 1 至多被使用一次。

注意:給定 0 和 1 的數量都不會超過 100。

給定字串陣列的長度不會超過 600。

示例 1:

輸入: array = , m = 5, n = 3

輸出: 4

解釋: 總共 4 個字串可以通過 5 個 0 和 3 個 1 拼出,即 "10","0001","1","0" 。

示例 2:

輸入: array = , m = 1, n = 1

輸出: 2

解釋: 你可以拼出 "10",但之後就沒有剩餘數字了。更好的選擇是拼出 "0" 和 "1" 。

思路:這個是乙個多維費用的0~1揹包問題,有兩個揹包大小,0和1的數量。

這個是我自己的乙個理解:這裡面是有兩個揹包,乙個是裝1的揹包,這個揹包的容量是m,另外乙個是裝0的揹包,這個揹包的容量是n。每乙個字串就相當於是乙個物品,其中0或者1的個數就是它的重量。這個題就是兩個揹包問題。

**:這個是我自己寫的乙個。出現了幾個錯誤,乙個是以為strs是字串,實際上是陣列,這個在求長度是時候要注意。還有就是在統計字串中0,1的個數時,不會使用把字串轉化為陣列。

class solution }}

return dp[m][n];}}

以下是更快的實現:

class solution

int dp = new int[m + 1][n + 1];

for (string s : strs) else

}for (int i = m; i >= zeros; i--) }}

return dp[m][n];}}

Leetcode揹包問題

題意 幾種無限數量的硬幣,湊成amount的方案數,方案是無序的,即1 2 和 2 1算同一種 題解 方法一 經典揹包解法 dp i j 表示前i個物品湊出j的方案數,考慮第i個選與不選兩種情況,其中選的時候,再考慮選擇第i個物品的次數。class solution return dp n amou...

leetcode筆記 揹包問題總結2

1.找零錢的最少硬幣數 322.coin change medium 題目 給定不同面額的硬幣 coins 和乙個總金額 amount。編寫乙個函式來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回 1。示例 1 輸入 coins 1,2,5 amount 11 輸...

leetcode的揹包問題

有n件物品和乙個容量為v的揹包。第i件物品的費用是w i 價值是v i 求將哪些物品裝入揹包可使價值總和最大。定義陣列 dp i j 代表前i個商品,放入乙個容量為j的揹包,所獲得的最大價值初始化 如果要求恰好放滿揹包,則陣列初始化為 inf dp inf amount 1 for in range...