我的 LeetCode 日記:Day 36 - 動態規劃,背包問題的千變萬化

昨天,我初步掌握了 0/1 背包問題的理論基礎和標準解法。今天,我將這種思想應用到了更廣泛的場景中。今天的幾道題,乍一看和背包沒什么關系,但通過巧妙的數學轉化,它們的核心都變成了 0/1 背包問題。

這讓我深刻體會到,學習算法不僅僅是學習模板,更重要的是學習一種建模能力——將一個看似全新的問題,轉化為我們熟悉的模型來求解。為了加深理解,我對每個適用的問題都同時實現了二維和一維的解法,以觀察它們之間的聯系和區別。

一、實戰演練:識別偽裝的背包問題

1. LeetCode 1049. 最后一塊石頭的重量 II

題目描述: 有一堆石頭,用整數數組 stones 表示。其中 stones[i] 是第 i 塊石頭的重量。每一回合,從中選出任意兩塊石頭,然后將它們一起粉碎…最后,最多只會剩下一塊石頭。返回此石頭最小的可能重量。

  • 學習感悟: 這個問題等價于將所有石頭分成兩堆 AB,并讓它們的重量差 |sum(A) - sum(B)| 最小。為了實現這一點,我們需要讓其中一堆的重量 sum(A) 盡可能地接近總重量的一半。這完美地轉化為了一個 0/1 背包問題:

    • 背包容量: target = total_sum // 2
    • 物品: stones 數組中的每一個 stone
    • 物品重量/價值: stone 的重量
    • 目標: 在容量為 target 的背包里,能裝下的最大重量是多少?
      在這里插入圖片描述
  • 資源包:
    * 題目/文章: https://programmercarl.com/1049.%E6%9C%80%E5%90%8E%E4%B8%80%E5%9D%97%E7%9F%B3%E5%A4%B4%E7%9A%84%E9%87%8D%E9%87%8FII.html
    * 視頻講解: https://www.bilibili.com/video/BV14M411C7oV

我的實現 1:二維 DP
class Solution:def lastStoneWeightII(self, stones: List[int]) -> int:total_sum = sum(stones)target = total_sum // 2n = len(stones)# dp[i][j]: 從0..i-1號石頭中任選,放入容量j的背包,能達到的最大重量dp = [[0] * (target + 1) for _ in range(n + 1)]for i in range(1, n + 1):stone_weight = stones[i - 1]for j in range(target + 1):if j < stone_weight:dp[i][j] = dp[i - 1][j] # 裝不下,不裝else:# 裝或者不裝dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - stone_weight] + stone_weight)sum_A = dp[n][target]sum_B = total_sum - sum_Areturn sum_B - sum_A
我的實現 2:一維 DP (空間優化)
class Solution:def lastStoneWeightII(self, stones: List[int]) -> int:total_sum = sum(stones)target = total_sum // 2# dp[j]:容量為j的背包,能裝下的最大重量dp = [0] * (target + 1)for stone_weight in stones:# 倒序遍歷,保證每個石頭只用一次for j in range(target, stone_weight - 1, -1):dp[j] = max(dp[j], stone_weight + dp[j - stone_weight])sum_A = dp[target]sum_B = total_sum - sum_Areturn sum_B - sum_A
2. LeetCode 494. 目標和

題目描述: 給你一個整數數組 nums 和一個整數 target 。向數組中的每個整數前添加 '+''-'。返回可以通過上述方法構造的、運算結果等于 target 的不同表達式的數目。

  • 學習感悟: 這道題是計數型 DP,但同樣可以轉化為背包問題。假設加 + 的子集和為 P,加 - 的子集和為 N。我們有 P - N = targetP + N = total_sum。兩式相加得 2P = target + total_sum,即 P = (target + total_sum) / 2
    • 背包模型: 問題變成了:從 nums 中挑選出一些數,使其和恰好為 new_target = (target + total_sum) / 2,共有多少種挑法?
    • DP 定義: dp[j] 表示和為 j 的組合有多少種。
  • 資源包:
    • 題目/文章: https://programmercarl.com/0494.%E7%9B%AE%E6%A0%87%E5%92%8C.html
    • 視頻講解: https://www.bilibili.com/video/BV1o8411j73x
我的實現 1:二維 DP
class Solution:def findTargetSumWays(self, nums: List[int], target: int) -> int:total_sum = sum(nums)if abs(target) > total_sum or (total_sum + target) % 2 != 0:return 0new_target = (total_sum + target) // 2n = len(nums)# dp[i][j]: 從0..i-1號數中任選,和為j的組合數dp = [[0] * (new_target + 1) for _ in range(n + 1)]dp[0][0] = 1 # 用0個數湊成和為0,有一種方法(什么都不選)for i in range(1, n + 1):num = nums[i - 1]for j in range(new_target + 1):if j < num:dp[i][j] = dp[i - 1][j] # 不選numelse:# 組合數 = (不選num的方法數) + (選num的方法數)dp[i][j] = dp[i - 1][j] + dp[i - 1][j - num]return dp[n][new_target]
我的實現 2:一維 DP (空間優化)
class Solution:def findTargetSumWays(self, nums: List[int], target: int) -> int:total_sum = sum(nums)if abs(target) > total_sum or (total_sum + target) % 2 != 0:return 0new_target = (total_sum + target) // 2# dp[j]:和為 j 的組合有多少種dp = [0] * (new_target + 1)dp[0] = 1for num in nums:# 倒序遍歷,保證每個數只用一次for j in range(new_target, num - 1, -1):dp[j] += dp[j - num]return dp[new_target]
3. LeetCode 474. 一和零

題目描述: 給你一個二進制字符串數組 strs 和兩個整數 mn 。請你找出 strs 的最大子集的長度,該子集中 最多m0n1

  • 學習感悟: 這道題是二維費用的 0/1 背包,是背包問題的一個重要變種。

    • 背包容量: 是一個二維的 (m, n),分別代表 01 的容量。
    • 物品: strs 數組中的每個字符串。
    • 物品重量: 每個字符串的重量也是二維的 (count_zeros, count_ones)
    • 物品價值: 每個字符串價值都是 1
  • DP 定義: dp[i][j] 表示用 i0j1 能構成的最大子集長度。

  • 狀態轉移: dp[i][j] = max(dp[i][j], 1 + dp[i - count_zeros][j - count_ones])

  • 遍歷順序: 因為是 0/1 背包,兩個表示容量的循環 ij必須倒序遍歷

  • 資源包:

    • 題目/文章: https://programmercarl.com/0474.%E4%B8%80%E5%92%8C%E9%9B%B6.html
    • 視頻講解: https://www.bilibili.com/video/BV1rW4y1x7ZQ
我的實現:二維費用背包
class Solution:def findMaxForm(self, strs: List[str], m: int, n: int) -> int:# dp[i][j]:用 i 個 0 和 j 個 1 能構成的最大子集長度dp = [[0] * (n + 1) for _ in range(m + 1)]for s in strs: # 遍歷物品count_zeros = s.count('0')count_ones = s.count('1')# 倒序遍歷背包的兩個維度容量for i in range(m, count_zeros - 1, -1):for j in range(n, count_ones - 1, -1):dp[i][j] = max(dp[i][j], 1 + dp[i - count_zeros][j - count_ones])return dp[m][n]

總結

今天我更深刻地理解了 0/1 背包問題的泛用性。它不僅僅是一個求最大價值的模型,通過改變 dp 數組的定義(求最大重量、求組合數、求可行性)和狀態轉移的方式,它可以解決各種各樣的問題。識別問題背后的背包模型,并正確地進行轉化,是解決這類 DP 問題的關鍵所在。從一維費用到二維費用,背包問題的世界真是廣闊。

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

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

相關文章

本地處理不上傳!隱私安全的PDF轉換解決方案

PDF能鎖定排版、字體、圖片位置&#xff0c;無論在什么設備打開都保持一致。它是無廣告、簡潔高效的專業PDF處理工具。功能豐富&#xff0c;支持批量操作&#xff1a;只需將文件拖入界面&#xff0c;選擇目標格式&#xff08;如Word、PPT、Excel、圖片等&#xff09;&#xff0…

Docker build創建鏡像命令入門教程

一、核心概念Dockerfile 定義鏡像構建步驟的文本文件&#xff0c;包含一系列指令和配置&#xff0c;用于自動化創建鏡像。鏡像層&#xff08;Layer&#xff09; Docker 鏡像由多層只讀層疊加而成&#xff0c;每個指令&#xff08;如 RUN、COPY&#xff09;會生成一個新的層。層…

Redis 是單線程模型嗎?

最近在面試中經常被問到這個問題&#xff1a;"Redis是單線程的嗎&#xff1f;"很多同學都會脫口而出&#xff1a;"是的&#xff01;"但其實這個答案并不完全正確。今天我們就來聊聊Redis的線程模型&#xff0c;把這個問題徹底搞清楚。 先說結論 Redis的線程…

Hologres實戰:路徑分析函數

前言 Hologres提供了一套高效的路徑分析函數&#xff0c;包括路徑明細計算和結果解析功能&#xff0c;能夠幫助用戶深入理解用戶行為路徑&#xff0c;并通過桑基圖實現數據可視化。 一、核心功能 路徑明細計算&#xff1a;精確記錄用戶在產品或功能中的完整訪問路徑結果解析…

產品開發實踐(常見的軟硬結合方式)

【 聲明&#xff1a;版權所有&#xff0c;歡迎轉載&#xff0c;請勿用于商業用途。 聯系信箱&#xff1a;feixiaoxing 163.com】前面說過&#xff0c;傳統的純軟件開發&#xff0c;在國內的大背景下面是很難存活的。但是如果是把軟件&#xff0c;構建在硬件基礎之上&#xff0c…

Linux | i.MX6ULL網絡通信-套字節 UDP(第十八章)

01 Linux | i.MX6ULL網絡通信-套字節 TCP(第十七章) 02 iTOP-IMX6ULL 實現基于 UDP 的 socket 編程。

學習嵌入式第三十天

文章目錄進程和線程&#xff08;續&#xff09;線程1.線程傳參2.線程屬性3.線程間通信1.概念2.方式3.互斥鎖4.死鎖5.信號量習題 進程和線程&#xff08;續&#xff09; 線程 1.線程傳參使用第四個參數實現對線程內部的傳參 代碼實現&#xff1a; #include <stdio.h> #inc…

GaussDB 數據庫架構師修煉(十三)安全管理(3)-行級訪問控制

1 背景行級訪問控制特性將數據庫的訪問控制精確到數據表行級別 &#xff0c;只允許用戶查看 、更新或刪除特定的行數據。2 實例場景實例以醫生只能看到治療的病人&#xff0c;不能看其它醫生的病人為例&#xff1a;1)醫院病人的信息表pat_info&#xff1a;csdn> set search_…

Wi-Fi 與蜂窩網絡(手機網絡)的核心區別,以及 Wi-Fi 技術未來的發展方向

在日常生活中&#xff0c;我們既離不開家里的 Wi-Fi&#xff0c;也離不開手機的 4G/5G 網絡。它們都能把我們連接到互聯網&#xff0c;但底層的工作方式卻大不相同。一、設計初衷的不同Wi-Fi誕生于 1997 年的 IEEE 802.11 標準&#xff0c;定位是局域網無線替代。它的目標是讓電…

C++編程實戰:高效解決算法與數據結構問題

個人主頁 &#xff1a; zxctscl 專欄 【C】、 【C語言】、 【Linux】、 【數據結構】、 【算法】 如有轉載請先通知 題目1. 數字統計2. 兩個數組的交集3. 牛牛的快遞4. 點擊消除5. 最小花費爬樓梯6. 簡寫單詞1. 數字統計 BC153 數字統計 #include <iostream> using na…

《零基礎入門AI:深度學習中的視覺處理(卷積神經網絡(CNN)進階)》

一、卷積知識擴展 1. 二維卷積 單通道版本 對于單通道輸入圖像 III (尺寸 HWH \times WHW) 和卷積核 KKK (尺寸 FFF \times FFF)&#xff0c;輸出特征圖 OOO 的計算公式為&#xff1a; O(i,j)∑m0F?1∑n0F?1I(im,jn)?K(m,n)O(i,j) \sum_{m0}^{F-1} \sum_{n0}^{F-1} I(im, j…

pyecharts可視化圖表-pie:從入門到精通(進階篇)

歡迎來到pyecharts餅圖系列教程的進階篇&#xff01;在上一篇基礎教程中&#xff0c;我們學習了餅圖的基本概念和簡單實現。在本文中&#xff0c;我們將深入探索pyecharts中餅圖的六種高級用法和自定義選項&#xff0c;包括環形餅圖、富文本標簽餅圖、滾動圖例餅圖、環形圖、嵌…

【JAVA 核心編程】面向對象高級:類變量與方法 抽象類與接口

一、類變量與類方法&#xff08;靜態變量&#xff09; 1&#xff09;類變量 class Child{private String name;//定義一個變量count&#xff0c;是一個類變量&#xff08;靜態變量&#xff09;static靜態//該變量最大的特點就是會被Child 類的所有對象訪問public static int co…

【Java基礎面試題】數據類型

Java面試高頻總結&#xff1a;基本數據類型深度解析 &#x1f4ca; 八種基本數據類型詳解數據類型關鍵字字節數位數默認值取值范圍核心特性字節型byte180-128 ~ 127最小整數類型短整型short2160-32,768 ~ 32,767較少使用整型int4320-2 ~ 2-1 (約21億)最常用整數類型長整型long8…

攻防世界—unseping(反序列化)

一.審題<?php highlight_file(__FILE__);class ease{private $method;private $args;function __construct($method, $args) {$this->method $method;$this->args $args;}function __destruct(){if (in_array($this->method, array("ping"))) {call_u…

AI熱點周報(8.10~8.16):AI界“冰火兩重天“,GPT-5陷入熱議,DeepSeek R2模型訓練受阻?

名人說&#xff1a;博觀而約取&#xff0c;厚積而薄發。——蘇軾《稼說送張琥》 創作者&#xff1a;Code_流蘇(CSDN)&#xff08;一個喜歡古詩詞和編程的Coder&#x1f60a;&#xff09; 目錄3分鐘速覽版&#xff1a;一張表看懂本周AI大事一、GPT-5&#xff1a;期待越高&#x…

Python_vue3_django旅拍在線婚紗攝影網站的設計與實現016023190_源碼LW_講解安裝

目錄前言-本系統介紹已開發項目效果實現截圖開發技術詳細介紹論文設計框架系統測試核心代碼參考示例總結源碼獲取詳細視頻演示或者查看其他版本&#xff1a;文章底部獲取博主聯系方式&#xff01;前言-本系統介紹 利用Python語言、MySQL數據庫&#xff0c;Django框架&#xff0…

Python爬蟲-爬取政務網站的文檔正文內容和附件數據

前言 本文是該專欄的第67篇,后面會持續分享python爬蟲干貨知識,記得關注。 本文,筆者以某政務網站為例子。基于Python爬蟲采集某政務網站的文檔正文內容和其關聯的附件數據。 具體的實現思路以及完整實現代碼邏輯,筆者將在正文進行詳細介紹。廢話不多說,跟著筆者直接往下…

Python:如何在Pycharm中顯示geemap地圖?

01 說明 或許在舊版本的python和jupyter中并不能成功. 作為參考&#xff0c;這里給出實驗成功的版本&#xff1a;名稱版本通道geemap0.36.1conda-forgejupyter1.1.1conda-forgepycharm2024.1.4 (Professional Edition)nullpython3.11.13conda-forge此外&#xff0c;由于顯示底圖…

力扣3:無重復字符的最長子串

力扣3:無重復字符的最長子串題目思路代碼題目 給定一個字符串 s &#xff0c;請你找出其中不含有重復字符的 最長 子串 的長度。 思路 這道題的思路其實是很簡單的&#xff0c;最后我們需要得到子串的長度所以我們可以定義兩個變量即子串的左邊界和右邊界這樣有了左右邊界就…