01揹包類演算法題

2021-07-26 21:50:36 字數 3521 閱讀 8864

關於揹包問題的概念可以參考此處

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

示例 1: 輸入: [1, 5, 11, 5],輸出: true

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

示例 2:輸入: [1, 2, 3, 5],輸出: false

其實可以看成是乙個01揹包問題。能不能裝滿sum/2,能的話就返回true,否則返回false。

public boolean canpartition(int nums) 

int sum = 0;

for (int num : nums)

if (sum % 2 != 0)

sum = sum / 2;

boolean res = new boolean[sum + 1];

res[0] = true;

for (int num : nums)

}return res[sum];

}

給定不同面額的硬幣 coins 和乙個總金額 amount。編寫乙個函式來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回 -1。

示例 1:

輸入: coins = [1, 2, 5], amount = 11 輸出: 3 解釋: 11 = 5 + 5 + 1

示例 2: 輸入: coins = [2], amount = 3  輸出: -1

說明:你可以認為每種硬幣的數量是無限的。

可以看成是乙個完全揹包問題。用乙個完全揹包裝滿指定的金額

public int coinchange(int coins, int amount) 

int dp = new int[amount + 1];

for (int coin : coins) else else }}

}}

return dp[amount] == 0 ? -1 : dp[amount];

}

給定不同面額的硬幣和乙個總金額。寫出函式來計算可以湊成總金額的硬幣組合數。假設每一種面額的硬幣有無限個。

示例 1: 輸入: amount = 5, coins = [1, 2, 5] 輸出: 4

解釋: 有四種方式可以湊成總金額:

5=55=2+2+1

5=2+1+1+1

5=1+1+1+1+1

示例 2: 輸入: amount = 3, coins = [2] 輸出: 0

解釋: 只用面額2的硬幣不能湊成總金額3。

因為每種面額是無限的,因此也是乙個完全揹包問題。

d 為動態規劃記錄陣列:

d[i] 代表,最多 i 元錢時可兌換的分配方案數量;

d[0] 時為初始條件,表示0元可以用0元兌換1次,所以 d[0] = 1。

d[i - c] 中,c 代表當前面值,d[i - c] 表示 i - c 元錢所有分配方案之和,d[i] 分配方案應該等於所有 d[i - c] 分配方案之和,這樣就可以快速的計算出 d[amount] 的和了。

public int change(int amount, int coins) 

int dp = new int[amount + 1];

dp[0] = 1;

for (int coin : coins)

}return dp[amount];

}

給定乙個非空字串 s 和乙個包含非空單詞列表的字典 worddict,判定 s 是否可以被空格拆分為乙個或多個在字典中出現的單詞。

說明:拆分時可以重複使用字典中的單詞。

你可以假設字典中沒有重複的單詞。

示例 1:輸入: s = "leetcode", worddict = ["leet", "code"]

輸出: true

解釋: 返回 true 因為 "leetcode" 可以被拆分成 "leet code"。

示例 3:輸入: s = "catsandog", worddict = ["cats", "dog", "sand", "and", "cat"]

輸出: false

因為可以重複使用,所以這是乙個經典的完全揹包問題,dp[i]表示從0到i能否拆分。

狀態轉移方程為:dp[i] = s[j-->i] in worddict and dp[j]。

注意 :需要定義dp[0]為 true,因為如果字串本身就在 worddict 中,就不必看 dp 了,可以直接判斷為 true,因此 dp[0] = true;

public boolean wordbreak(string s, listworddict) 

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

setset = new hashset<>(worddict);

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

dp[0] = true;

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

return dp[s.length()];

}

給定乙個由正整數組成且不存在重複數字的陣列,找出和為給定目標正整數的組合的個數。

示例: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。

此題的狀態轉移方程為dp[i] = dp[i-nums[0]]+dp[i-nums[1]]+...dp[i-nums[len-1]],條件為i>=nums[j];

dp[0] = 1,dp[0]表示組成0,乙個數都不選就可以了,所以dp[0]=1

舉個例子。假設nums=; target = 4

dp[4] = dp[4-1]+dp[4-2]+dp[4-3] = dp[3]+dp[2]+dp[1]

dp[1] = dp[0] = 1;

dp[2] = dp[1]+dp[0] = 2;

dp[3] = dp[2]+dp[1]+dp[0] = 4;

dp[4] = dp[4-1]+dp[4-2]+dp[4-3] = dp[3]+dp[2]+dp[1] = 7

**如下

public int combinationsum4(int nums, int target) 

int dp = new int[target + 1];

//dp[0]表示組成0,乙個數都不選就可以了,所以dp[0]=1

dp[0] = 1;

for (int i = 1; i <= target; i++) }}

return dp[target];

}

01揹包演算法

核心 狀態轉換方程 01揹包問題 容量為10的揹包,有5種物品,每種物品只有乙個,其重量分別為5,4,3,2,1,其價值分別為1,2,3,4,5。設計演算法,實現揹包內物品價值最大。如下 輸出14 include include using namespace std int main int v ...

演算法 01揹包

揹包最大容量10,有以下5個商品及其價值,試求揹包所能容納的最大價值。序號1 2345 重量226 54價值6 3546 如下 include include define max v 100 using namespace std struct good 動態規劃求解 n 商品個數 m 揹包最大重...

01揹包演算法

01揹包問題 動態規劃的基本思想 動態規劃演算法可分解成從先到後的4個步驟 1.描述乙個最優解的結構,尋找子問題,對問題進行劃分。2.定義狀態。往往將和子問題相關的各個變數的一組取值定義為乙個狀態。某個狀態的值就是這個子問題的解 若有k個變數,一般用k維的陣列儲存各個狀態下的解,並可根 據這個陣列記...