背包問題(動歸)

目錄

問能否能裝滿背包(或者最多裝多少):dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]); 對應題目如下:

416.分割等和子集 (物品正序,背包倒序)

問裝滿背包有幾種方法:dp[j] += dp[j - nums[i]] ,對應題目如下:

518. 零錢兌換 II(opens new window)

問背包裝滿最大價值:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); ,對應題目如下:

474.一和零

問裝滿背包所有物品的最小個數:dp[j] = min(dp[j - coins[i]] + 1, dp[j]); ,對應題目如下:

322.零錢兌換(最少個數) 正序 先物品再背包

279.完全平方數(最小數量) 先背包后物品

遍歷順序

01背包

完全背包


背包問題,大家都知道,有N件物品和一個最多能背重量為W 的背包。第i件物品的重量是weight[i],得到的價值是value[i] 。每件物品只能用一次,求解將哪些物品裝入背包里物品價值總和最大。

背包問題有多種背包方式,常見的有:01背包、完全背包、多重背包、分組背包和混合背包等等。

要注意題目描述中商品是不是可以重復放入。

一個商品如果可以重復多次放入是完全背包,而只能放入一次是01背包,寫法還是不一樣的。

問能否能裝滿背包(或者最多裝多少):dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]); 對應題目如下:
416.分割等和子集 (物品正序,背包倒序)

給你一個 只包含正整數 非空 數組 nums 。請你判斷是否可以將這個數組分割成兩個子集,使得兩個子集的元素和相等。


這道題目就是一道01背包應用類的題目,需要我們拆解題目,然后套入01背包的場景。

01背包相對于本題,主要要理解,題目中物品是nums[i],重量是nums[i],價值也是nums[i],背包體積是sum/2。

class Solution {public boolean canPartition(int[] nums) {/*** 1. 確定dp數組及下標含義 :容量為j的背包,所背的物品價值最大可以為dp[j],背包價值等于總和的一半* 2. 遞推公式 dp[j]=Math.max(dp[j],dp(j-nums[i])+nums[i])* 3. 初始化 dp[0]=0 非零dp[]:0 只包含正整數的非空數組,所以非0下標的元素初始化為0* 4. 遍歷順序 dp[j] 如果使用一維dp數組,物品遍歷的for循環放在外層,遍歷背包的for循環放在內層,且內層for循環倒序遍歷!* 5. 推導結果*/if (nums == null || nums.length == 0) {return false;}int sum = 0;for (int num : nums) {sum += num;}//總和為奇數不能平分if (sum % 2 != 0) {return false;}int target = sum / 2;int[] dp = new int[target + 1];for (int i = 0; i < nums.length; i++) {//物品for (int j = target; j >= nums[i]; j--) {//背包 倒序遍歷dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);}//剪枝一下,每一次完成for-loop,立即檢查是否dp[target] == targetif (dp[target] == target) {return true;}}return dp[target] == target;}
}
  • 動態規劃:1049.最后一塊石頭的重量 II(opens new window)
問裝滿背包有幾種方法:dp[j] += dp[j - nums[i]] ,對應題目如下:
  • 動態規劃:494.目標和(opens new window)
518. 零錢兌換 II(opens new window)

給你一個整數數組 coins 表示不同面額的硬幣,另給一個整數 amount 表示總金額。

請你計算并返回可以湊成總金額的硬幣組合數。如果任何硬幣組合都無法湊出總金額,返回 0 。

假設每一種面額的硬幣有無限個。


/*** 先物品后背包的情況下,根據遞推公式,dp【j】一定是來自于外層上一次的結果,而外層上一次的結果一定是來源于上一個物品的dp數組,所以不會出現物品2在物品1之前的情況,也就是只會出現【物品1,物品1,物品2】這種情況,而物品2不會出現在物品1之前,(不會重復)恰好對應組合問題;* 而外層遍歷背包 內層遍歷物品就不一樣了,每一層的dp【j】都是在固定j的情況下,把物品從頭開始遍歷,所以dp【j】來自于上一層的結果,而上一層的結果又遍歷了所有物品,所以這種遍歷方式會出現【物品1,物品2,物品1】這種情況,恰好對應了排列問題* 組合不強調元素之間的順序,排列強調元素之間的順序。* * 1.dp[j]:湊成總金額j的貨幣組合數為dp[j]* 2.dp[j] 就是所有的dp[j - coins[i]](考慮coins[i]的情況)相加。* dp[j] += dp[j - coins[i]];* 3.初始化  dp[0] = 1 下標非0的dp[j]初始化為0,這樣累計加dp[j - coins[i]]的時候才不會影響真正的dp[j]* 4.遍歷順序 先物品后背包* 如果求組合數就是外層for循環遍歷物品,內層for遍歷背包。* 如果求排列數就是外層for遍歷背包,內層for循環遍歷物品。*/
class Solution {public int change(int amount, int[] coins) {int[] dp = new int[amount + 1];dp[0]=1;//判斷條件決定遍歷的背包還是物體  求的是組合數for (int i = 0; i <coins.length; i++) {//物品   for (int j = coins[i]; j <=amount ; j++) {//背包  價值到背包dp[j]+=dp[j-coins[i]];}}return dp[amount];}
}
  • 動態規劃:377.組合總和Ⅳ(opens new window)
  • 動態規劃:70. 爬樓梯進階版(完全背包)(opens new window)
問背包裝滿最大價值:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); ,對應題目如下:
474.一和零

給你一個二進制字符串數組 strs 和兩個整數 m 和 n 。

請你找出并返回 strs 的最大子集的長度,該子集中 最多 有 m 個 0 和 n 個 1

如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集

問裝滿背包所有物品的最小個數:dp[j] = min(dp[j - coins[i]] + 1, dp[j]); ,對應題目如下:

完全背包統一正序遍歷

322.零錢兌換(最少個數) 正序 先物品再背包

給你一個整數數組 coins ,表示不同面額的硬幣;以及一個整數 amount ,表示總金額。

計算并返回可以湊成總金額所需的 最少硬幣個數 。如果沒有任何一種硬幣組合能組成總金額,返回 -1 。

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

class Solution {/*** 1.確定dp數組以及下標的含義* dp[i]: 湊足總額為j所需錢幣的最少個數為dp[j]* 2.遞推公式 在進行遞推公式之前通常有對應的條件判斷* dp[j] = Math.min(dp[j - coins[i]] + 1, dp[j]);* 3.初始化* dp[0]=0 dp[j]初始化成比較大的數,防止被覆蓋* 4.遍歷順序 完全背包(個數不受限制)* 完全背包是正序遍歷 求組合數就是外層for循環遍歷物品,內層for遍歷背包。求排列數就是外層for遍歷背包,內層for循環遍歷物品。*/public int coinChange(int[] coins, int amount) {//初始化dp數組為最大值int max = Integer.MAX_VALUE;//錢數需要的最少硬幣int[] dp = new int[amount + 1];Arrays.fill(dp, max);//初始化dp[0] = 0;for (int i = 0; i < coins.length; i++) { //遍歷物品//正序遍歷:完全背包問題  每個硬幣可以選擇多次for (int j = coins[i]; j <= amount; j++) {//只有dp[j-coins[i]]不是初始最大值時,才有選擇的必要//在進行遞推公式之前通常有對應的條件判斷if (dp[j - coins[i]] != max) {//選擇硬幣數目最小的情況dp[j] = Math.min(dp[j - coins[i]] + 1, dp[j]);}}}//三目運算符比較好用 沒有最小值就返回-1return dp[amount]== max ? -1 : dp[amount];}
}
279.完全平方數(最小數量) 先背包后物品

給你一個整數 n ,返回 和為 n 的完全平方數的最少數量

class Solution {public int numSquares(int n) {/*** 完全平方數就是物品(可以無限件使用),湊個正整數n就是背包,問湊滿這個背包最少有多少物品?* 1.確定dp數組以及下標的含義* dp[i]: 和為 j 的完全平方數的最少數量為dp[j]* 2.遞推公式 在進行遞推公式之前通常有對應的條件判斷* dp[j] = Math.min(dp[j - i*i] + 1, dp[j]);* 3.初始化* dp[0]=0 dp[j]初始化成比較大的數,防止被覆蓋* 4.遍歷順序 完全背包(個數不受限制)* 完全背包是正序遍歷* 求排列數就是外層for遍歷背包,內層for循環遍歷物品。*/// 定義:和為 i 的平方數的最小數量是 dp[i]int[] dp = new int[n + 1];Arrays.fill(dp, Integer.MAX_VALUE);// base casedp[0] = 0;// 狀態轉移方程for (int i = 1; i <= n; i++) {for (int j = 1; j * j <= i; j++) {// i - j * j 只要再加一個平方數 j * j 即可湊出 idp[i] = Math.min(dp[i], dp[i - j * j] + 1);}}return dp[n];}        `                    
}
遍歷順序
01背包

在動態規劃:關于01背包問題,你該了解這些! (opens new window)中我們講解二維dp數組01背包先遍歷物品還是先遍歷背包都是可以的,且第二層for循環是從小到大遍歷。

和動態規劃:關于01背包問題,你該了解這些!(滾動數組) (opens new window)中,我們講解一維dp數組01背包只能先遍歷物品再遍歷背包容量,且第二層for循環是從大到小遍歷。

完全背包

在動態規劃:關于完全背包,你該了解這些! (opens new window)中,講解了純完全背包的一維dp數組實現,先遍歷物品還是先遍歷背包都是可以的,且第二層for循環是從小到大遍歷。

但是僅僅是純完全背包的遍歷順序是這樣的,題目稍有變化,兩個for循環的先后順序就不一樣了。

如果求組合數就是外層for循環遍歷物品,內層for遍歷背包。

如果求排列數就是外層for遍歷背包,內層for循環遍歷物品。

相關題目如下:

  • 求組合數:動態規劃:518.零錢兌換II(opens new window)
  • 求排列數:動態規劃:377. 組合總和 Ⅳ (opens new window)、動態規劃:70. 爬樓梯進階版(完全背包)(opens new window)

如果求最小數,那么兩層for循環的先后順序就無所謂了,相關題目如下:

  • 求最小數:動態規劃:322. 零錢兌換 (opens new window)、動態規劃:279.完全平方數(opens new window)

對于背包問題,其實遞推公式算是容易的,難是難在遍歷順序上,如果把遍歷順序搞透,才算是真正理解了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/35927.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/35927.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/35927.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

父級設置最大寬度,其寬度自適應子級中的內容

父級寬度自適應 1.父級限制最大寬度 2.子級豎著排放,每列的個數明確 3.父級的寬度跟隨子級元素的個數變化寬度 tips: 因為父級要設置"background-color"屬性,所以父級DIV必須要給明確的寬高,這就意味著純CSS自適應寬度無法做到(好吧,是我做不到) HTML <temp…

茴香豆接入微信個人助手部署

將rag產品接入微信工作群&#xff0c;自動回答問題&#xff0c;香嗎&#xff1f;&#xff1f; let‘s go 1、打開openxlab平臺&#xff0c;找到茴香豆web產品應用中心-OpenXLab 點擊進入&#xff0c;設置知識庫名字和密碼 2、上傳知識庫文件和編輯正反例等 3、然后進行測試問答…

電腦開機之后屏幕沒有任何顯示?怎么檢查?

前言 最近有很多小伙伴來咨詢&#xff0c;自己的電腦開機之后&#xff0c;屏幕真的是一點顯示都沒有&#xff0c;只有CPU風扇在轉。 這個情況小白經常經常經常遇到&#xff0c;所以寫一篇關于這個問題的排查教程。按照這個教程來排查&#xff0c;除非真的是硬件損壞&#xff…

算法第八天:leetcode234.回文鏈表

給你一個單鏈表的頭節點 head &#xff0c;請你判斷該鏈表是否為回文鏈表。如果是&#xff0c;返回 true &#xff1b;否則&#xff0c;返回 false 。 示例 1&#xff1a; 輸入&#xff1a;head [1,2,2,1] 輸出&#xff1a;true示例 2&#xff1a; 輸入&#xff1a;head [1,2…

面向對象編程——python

目錄 一、面向對象編程 1.1 類和對象 1.2 繼承 1.3 封裝 1.4 多態 1.5 Python中的面向對象編程 二、類、對象和變量 2.1 類&#xff08;Class&#xff09; 2.2.1 類的屬性&#xff08;Class Attributes&#xff09; 2.2.2 類的方法&#xff08;Class Methods…

對類與對象的(二)補充

1.Date這樣的構造函數 析構函數 拷貝構造 默認構造函數有三種 &#xff1a;全缺省的構造函數 無參的構造函數 和編譯器默認生成的構造函數 class Date {pubilc&#xff1a;void Print&#xff08;&#xff09; { } private&#xff1a;//全缺省的int year1;int month1;int …

二叉樹的廣度優先搜索(層次遍歷)

目錄 定義 層序遍歷的數據結構 實現過程簡述 具體代碼 定義 層序遍歷就是從左到右一層一層地遍歷二叉樹。 層序遍歷的數據結構 層序遍歷需要借用一個輔助數據結構實現&#xff0c;由于隊列具有先進先出的特性&#xff0c;符合一層一層遍歷的邏輯&#xff0c;而棧先進后出…

PHP框架之Laravel框架

Laravel框架詳解 Laravel&#xff0c;作為一款廣受歡迎的PHP Web開發框架&#xff0c;以其優雅、簡潔的語法和強大的功能特性&#xff0c;贏得了全球眾多開發者的青睞。下面&#xff0c;我們將從Laravel的特點、應用案例以及具體的框架使用等方面進行詳細解析。 一、Laravel框…

甲子光年專訪天潤融通CEO吳強:客戶經營如何穿越低速周期?

作者&#xff5c;陳楊、編輯&#xff5c;栗子 社會的發展從來都是從交流和聯絡開始的。 從結繩記事到飛馬傳信&#xff0c;從電話電報到互聯網&#xff0c;人類的聯絡方式一直都在隨著時代的發展不斷進步。只是傳統社會通信受限于技術導致效率低下&#xff0c;對經濟社會產生影…

LLaMA:挑戰大模型Scaling Law的性能突破

實際問題 在大模型的研發中,通常會有下面一些需求: 計劃訓練一個10B的模型,想知道至少需要多大的數據?收集到了1T的數據,想知道能訓練一個多大的模型?老板準備1個月后開發布會,給的資源是100張A100,應該用多少數據訓多大的模型效果最好?老板對現在10B的模型不滿意,想…

退市新規解讀—財務類強制退市

一、退市風險警示&#xff1a;第一年觸及相關指標 上市公司最近一個會計年度觸及下列退市風險指標之一&#xff0c;公司股票或存托憑證被實施退市風險警示(*ST)&#xff1a; 第1項 組合類財務指標 僅發行A股或B股&#xff0c;最近一個會計年度或追溯重述后最近一個會計年度 …

Leetcode 102.目標和

給定一個正整數數組 nums 和一個整數 target 。 向數組中的每個整數前添加 ‘’ 或 ‘-’ &#xff0c;然后串聯起所有整數&#xff0c;可以構造一個 表達式 &#xff1a; 例如&#xff0c;nums [2, 1] &#xff0c;可以在 2 之前添加 ‘’ &#xff0c;在 1 之前添加 ‘-’ &…

C#面:C#屬性能在接口中聲明嗎?

在C#中&#xff0c;接口是一種定義了一組方法、屬性和事件的類型。在接口中&#xff0c;只能聲明方法、屬性和事件的簽名&#xff0c;而不能包含字段、構造函數或實現代碼。因此&#xff0c;C#屬性不能直接在接口中聲明。 然而&#xff0c;你可以在接口中定義屬性的簽名&#…

VMware的具體使用

&#x1f4d1;打牌 &#xff1a; da pai ge的個人主頁 &#x1f324;?個人專欄 &#xff1a; da pai ge的博客專欄 ??寶劍鋒從磨礪出&#xff0c;梅花香自苦寒來 目錄 一&#x1f324;?VMware的安…

用戶登錄錯誤次數太多鎖定賬號

當用戶登錄驗證碼錯誤次數太多時&#xff0c;需要限制用戶在10分鐘之內不能再次登錄。 限制方案&#xff1a; 1.通過Redis ZSet key可以設置為用戶名&#xff0c;value可以設置為UUID&#xff0c;score設置為當前時間戳 每次用戶登錄時&#xff0c;通過 rangeByScore 查詢對…

Ubuntu22安裝PyCharm

下載&#xff08;社區版&#xff09; 官網下載地址 解壓 sudo tar -xzvf pycharm-community-2024.1.4.tar.gz 軟件移動到指定目錄下&#xff08;根據不同版本修改&#xff09; sudo mv pycharm-community-2024.1.4/ /usr/local/PyCharm/運行 cd /usr/local/PyCharm/pycha…

使用PEFT庫進行ChatGLM3-6B模型的LORA高效微調

PEFT庫進行ChatGLM3-6B模型LORA高效微調 LORA微調ChatGLM3-6B模型安裝相關庫使用ChatGLM3-6B模型GPU顯存占用準備數據集加載模型加載數據集數據處理數據集處理配置LoRA配置訓練超參數開始訓練保存LoRA模型模型推理從新加載合并模型使用微調后的模型 LORA微調ChatGLM3-6B模型 本…

6 序列數據和文本的深度學習

6.1 使用文本數據 文本是常用的序列化數據類型之一。文本數據可以看作是一個字符序列或詞的序列。對大多數問題&#xff0c;我們都將文本看作詞序列。深度學習序列模型(如RNN及其變體)能夠從文本數據中學習重要的模式。這些模式可以解決類似以下領域中的問題&#xff1a; 自然…

JVM專題十一:JVM 中的收集器一

上一篇JVM專題十&#xff1a;JVM中的垃圾回收機制專題中&#xff0c;我們主要介紹了Java的垃圾機制&#xff0c;包括垃圾回收基本概念&#xff0c;重點介紹了垃圾回收機制中自動內存管理與垃圾收集算法。如果說收集算法是內存回收的方法論&#xff0c;那么垃圾收集器就是內存回…

【開發者推薦】告別繁瑣:一鍵解鎖國產ETL新貴,Kettle的終結者

在數字化轉型的今天&#xff0c;數據集成的重要性不言而喻。ETL工具作為數據管理的核心&#xff0c;對企業決策和運營至關重要。盡管Kettle廣受歡迎&#xff0c;但國產ETL工具 TASKCTL 以其創新特性和卓越性能&#xff0c;為市場提供了新的選擇。 TASKCTL概述 TASKCTL 是一款免…