算法與數據結構:動態規劃DP

文章目錄

      • 動態規劃算法全面解析
        • 一、核心思想與基本概念
        • 二、動態規劃與其他算法的區別
        • 三、動態規劃的解題步驟
        • 四、經典案例解析
          • 1. **斐波那契數列(Fibonacci)**
          • 2. **0-1背包問題(0-1 Knapsack)**
          • 3. **最長公共子序列(LCS)**
        • **五、動態規劃的優化技巧**
        • **六、動態規劃的應用場景**
        • **七、動態規劃與貪心的對比**
        • **八、學習建議**

動態規劃算法全面解析

動態規劃(Dynamic Programming,DP)是一種通過將復雜問題分解為重疊子問題,并利用子問題的解來高效解決原問題的算法思想。它與分治法類似,但更注重對重復子問題的優化,避免重復計算,從而大幅提升算法效率。

一、核心思想與基本概念
  1. 重疊子問題(Overlapping Subproblems)
    問題可以分解為多次重復出現的子問題。例如斐波那契數列中,計算fib(n)時需要重復計算fib(n-1)fib(n-2)

  2. 最優子結構(Optimal Substructure)
    問題的最優解包含子問題的最優解。例如最短路徑問題中,從A到C的最短路徑必然包含A到B的最短路徑(若B是路徑中的節點)。

  3. 狀態轉移方程
    用數學公式定義子問題之間的關系,是動態規劃的核心。例如斐波那契數列的狀態轉移方程為:
    f i b ( n ) = { 0 , n = 0 1 , n = 1 f i b ( n ? 1 ) + f i b ( n ? 2 ) , n > 1 fib(n) = \begin{cases} 0, & n=0 \\ 1, & n=1 \\ fib(n-1) + fib(n-2), & n>1 \end{cases} fib(n)=? ? ??0,1,fib(n?1)+fib(n?2),?n=0n=1n>1?

二、動態規劃與其他算法的區別
算法類型核心策略重復子問題處理典型案例
動態規劃利用子問題解存儲與復用存儲結果避免重復計算背包問題、最長公共子序列
分治法將問題分解為獨立子問題不存儲子問題解歸并排序、快速冪
貪心算法每一步選擇局部最優解不考慮子問題重疊霍夫曼編碼、活動選擇問題
三、動態規劃的解題步驟
  1. 定義狀態
    明確dp[i]表示什么,通常與問題的規模或階段相關。例如:

    • dp[i]:長度為i的序列的最優解
    • dp[i][j]:二維問題中第i行第j列的狀態
  2. 推導狀態轉移方程
    找出dp[i]dp[i-1]dp[i-2]等子狀態的關系,例如:

    • 背包問題:dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i])
    • 最長遞增子序列(LIS):dp[i] = max(dp[j] + 1) ,其中j < i且nums[j] < nums[i]
  3. 確定初始條件
    處理最小規模的子問題,例如:

    • dp[0] = 0(空序列的解)
    • dp[i][0] = 0(背包容量為0時無法裝物品)
  4. 確定計算順序
    確保計算dp[i]時,其依賴的子狀態已被計算,通常采用自底向上(迭代)的方式。

  5. 獲取最終結果
    根據問題要求,從狀態數組中提取答案(可能是dp[n]max(dp[1..n])等)。

四、經典案例解析
1. 斐波那契數列(Fibonacci)
  • 問題:計算第n個斐波那契數。
  • 暴力遞歸:時間復雜度O(2^n),存在大量重復計算。
  • 動態規劃解法
    def fib_dp(n):if n <= 1:return ndp = [0] * (n + 1)dp[0], dp[1] = 0, 1for i in range(2, n + 1):dp[i] = dp[i-1] + dp[i-2]return dp[n]
    
  • 優化:只需存儲前兩個狀態,空間復雜度從O(n)降為O(1)
    def fib_optimized(n):if n <= 1:return na, b = 0, 1for _ in range(2, n + 1):a, b = b, a + breturn b
    
2. 0-1背包問題(0-1 Knapsack)
  • 問題:有n個物品,每個物品重量w[i]、價值v[i],背包容量W,求能裝的最大價值。
  • 狀態定義dp[i][j]表示前i個物品放入容量為j的背包的最大價值。
  • 狀態轉移
    • 不選第i個物品:dp[i][j] = dp[i-1][j]
    • 選第i個物品(若j >= w[i]):dp[i][j] = dp[i-1][j-w[i]] + v[i]
    • 最終:dp[i][j] = max(不選, 選)
  • 代碼實現
    def knapsack(w, v, W):n = len(w)dp = [[0] * (W + 1) for _ in range(n + 1)]for i in range(1, n + 1):for j in range(W + 1):if w[i-1] <= j:dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i-1]] + v[i-1])else:dp[i][j] = dp[i-1][j]return dp[n][W]
    
  • 空間優化:使用一維數組,逆序更新(避免重復使用當前物品):
    def knapsack_optimized(w, v, W):n = len(w)dp = [0] * (W + 1)for i in range(n):for j in range(W, w[i] - 1, -1):dp[j] = max(dp[j], dp[j - w[i]] + v[i])return dp[W]
    
3. 最長公共子序列(LCS)
  • 問題:求兩個字符串AB的最長公共子序列長度。
  • 狀態定義dp[i][j]表示A[0..i-1]B[0..j-1]的LCS長度。
  • 狀態轉移
    • A[i-1] == B[j-1]dp[i][j] = dp[i-1][j-1] + 1
    • 否則:dp[i][j] = max(dp[i-1][j], dp[i][j-1])
  • 代碼示例
    def lcs_length(text1, text2):m, n = len(text1), len(text2)dp = [[0] * (n + 1) for _ in range(m + 1)]for i in range(1, m + 1):for j in range(1, n + 1):if text1[i-1] == text2[j-1]:dp[i][j] = dp[i-1][j-1] + 1else:dp[i][j] = max(dp[i-1][j], dp[i][j-1])return dp[m][n]
    
五、動態規劃的優化技巧
  1. 空間壓縮

    • 一維DP:將二維狀態數組壓縮為一維(如0-1背包的優化)。
    • 滾動數組:僅保留與當前狀態相關的前幾個子狀態(如斐波那契數列)。
  2. 狀態轉移優化

    • 利用數據結構(如平衡樹、單調隊列)加速狀態轉移。
    • 矩陣快速冪:將線性遞推關系轉化為矩陣乘法,適用于大規模數據。
  3. 記憶化搜索(自頂向下)

    • 用遞歸+緩存的方式避免重復計算,適合子問題依賴關系復雜的場景。
    def fib_memo(n, memo={}):if n in memo:return memo[n]if n <= 1:memo[n] = nelse:memo[n] = fib_memo(n-1, memo) + fib_memo(n-2, memo)return memo[n]
    
六、動態規劃的應用場景
  • 組合優化問題:背包問題、旅行商問題(TSP)、最短路徑。
  • 字符串處理:編輯距離、最長回文子串、正則表達式匹配。
  • 數學問題:硬幣找零、整數拆分、矩陣鏈乘法。
  • 概率與統計:股票買賣最佳時機、骰子點數組合。
  • 圖論問題:狀態壓縮DP(如哈密頓路徑)。
七、動態規劃與貪心的對比
  • 動態規劃:考慮所有可能的子問題,確保全局最優,但時間復雜度較高。
  • 貪心算法:每一步選局部最優,可能無法得到全局最優,但效率更高。
  • 案例對比
    • 活動選擇問題:貪心可直接選結束時間最早的活動,無需DP。
    • 背包問題:貪心(按單位重量價值選)無法得到最優解,必須用DP。
八、學習建議
  1. 從基礎案例入手:先掌握斐波那契、背包、LCS等經典問題。
  2. 多練習狀態定義:動態規劃的核心難點在于狀態轉移方程的推導。
  3. 注意邊界條件:初始狀態的設定直接影響結果正確性。
  4. 分析時間與空間復雜度:優化算法時需平衡兩者。
  5. 參考解題模板:許多DP問題有固定的狀態設計模式(如區間DP、樹形DP)。

動態規劃是算法設計中最具挑戰性的思想之一,但通過大量練習和總結,能夠有效提升解決復雜問題的能力。

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

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

相關文章

Coilcraft電感上的橫線是什么意思?電感有方向么?

通常我們會認為電容、電感、電阻這幾類無源器件沒有方向性&#xff0c;在布局和貼片時可以任意方向放置&#xff0c;也不會在PCB上增加絲印標識說明其方向。與此相互印證的是&#xff0c;電容表面無絲印&#xff0c;無法識別方向&#xff1b;電阻表面一般只有包含阻值大小的數字…

通過Docker掛載nginx并修改頁面

1&#xff1a;通過docker創建nginx&#xff1a; 首先關閉原來的Docker&#xff08;防止端口號沖突&#xff09; sudo nginx -s stop 直接啟動 Nginx 進程 sudo nginx 啟動nginx&#xff1a; docker run -di --namemynginx -p 80:80 nginx cd /etc/nginx docker run -d …

力扣1124. 表現良好的最長時間段

這一題我看到數據范圍是10^4&#xff0c;暗自竊喜能用雙重循環&#xff0c;看題目是典型的前綴和哈希。不過需要一個轉換將大于8小時的轉化為1&#xff0c;其他都為-1&#xff0c;方便計算&#xff0c;之前的題目中也有這種方法。 那這樣就簡單了 class Solution { public:int…

EDA2算法速通(編者崩潰版)

這個內容是用來回憶一下EDA2涉及的算法和解題的主要步驟&#xff1a; 有疑問或發現錯誤可以私信來討論 高級綜合概述 柏拉圖優化&#xff1a;這個是來判斷是否有哪些節點能完全被其他節點優化掉。比如&#xff08;1,2&#xff09;這個節點就可以完全優化&#xff08;3,4&…

雷池waf配置第三方登錄-釘釘配置詳細教程

雷池waf配置第三方登錄-釘釘配置詳細教程 前往釘釘開放平臺https://open.dingtalk.com/ 選擇一個登錄方式登錄釘釘開放平臺 選擇一個自己所管理的組織 登錄成功后點擊我的后臺 選擇應用開發 在釘釘應用下點擊創建應用 填寫應用名稱和應用描述后點擊保存 點擊網頁…

神經網絡中的均方誤差(Mean Squared Error)詳解

引言 在機器學習和神經網絡領域&#xff0c;損失函數&#xff08;Loss Function&#xff09;是衡量模型預測值與真實值之間差異的關鍵指標。均方誤差&#xff08;Mean Squared Error, MSE&#xff09;作為一種經典的損失函數&#xff0c;因其簡單性、可解釋性和數學上的優良性…

day036-lsyncd實時同步服務與網站存儲架構

文章目錄 1. 實時同步工具2. lsyncd 實時同步服務2.1 環境準備2.2 rsync準備2.2.1 服務端檢查2.2.2 客戶端檢查2.2.3 備份測試 2.3 配置lsyncd2.3.1 安裝軟件2.3.2 編寫配置文件 2.4 測試 3. 案例-網站存儲架構3.1 rsync服務配置3.1.1 服務端配置3.1.2 客戶端配置 3.2 lsyncd服…

React Native WebView鍵盤難題:如何讓輸入框不被鍵盤遮擋?

寫在前面 “明明點擊了輸入框&#xff0c;鍵盤卻把內容頂得不見蹤影&#xff01;” —— 這可能是React Native開發者使用WebView時最頭疼的問題之一。 想象一下&#xff1a;你的App內嵌了一個網頁表單&#xff0c;用戶興奮地準備填寫信息&#xff0c;結果鍵盤彈出后&#xf…

Web攻防-XSS跨站瀏覽器UXSS突變MXSSVueReactElectron框架JQuery庫寫法和版本

知識點&#xff1a; 1、Web攻防-XSS跨站-瀏覽器&轉換-UXSS&MXSS 2、Web攻防-XSS跨站-框架和庫-VUE&React&Electron&JQuery 分類&#xff1a; 1、框架或三方庫的XSS(Vue、React、Electron、JQuery) 2、瀏覽器或插件的XSS(UXSS) 3、客戶端預覽內核的XSS(MXS…

PyTorch 中torch.clamp函數使用詳解和實戰示例

torch.clamp 是 PyTorch 中的一個非常有用的函數&#xff0c;它可以將張量的每個元素限制在一個指定的范圍內&#xff0c;超出范圍的元素將被裁剪為邊界值。 函數簽名&#xff1a; torch.clamp(input, minNone, maxNone, outNone)參數說明&#xff1a; input&#xff1a;輸入…

詳解Redis數據庫和緩存不一致的情況及解決方案

數據庫與緩存不一致是分布式系統中常見問題&#xff0c;本質是數據在緩存層和存儲層出現版本差異。 一、并發寫操作導致不一致&#xff08;最常見&#xff09; 場景描述 線程A更新數據庫 → 線程B更新數據庫 → 線程B更新緩存 → 線程A更新緩存 結果&#xff1a;緩存中存儲的…

湖北理元理律師事務所:企業債務危機的“急診科”式應對方案

當企業陷入債務危機時&#xff0c;傳統“頭痛醫頭”的應對往往加速死亡。本方案基于企業債務重組實務&#xff0c;提煉出 “止血-清創-修復”三階急救體系&#xff0c;助力企業守住生存底線。 第一階段&#xff1a;精準止血&#xff08;0-30天關鍵期&#xff09; 目標&#x…

華為云Flexus+DeepSeek征文|基于Dify構建智能票據信息識別助手

華為云FlexusDeepSeek征文&#xff5c;基于Dify構建智能票據信息識別助手 一、構建智能票據信息識別助手前言二、構建智能票據信息識別助手環境2.1 基于FlexusX實例的Dify平臺2.2 基于MaaS的模型API商用服務 三、構建智能票據信息識別助手實戰3.1 配置Dify環境3.2 配置Dify工具…

Python實例題:基于聯邦學習的隱私保護 AI 系統(分布式學習、隱私計算)

目錄 Python實例題 題目 問題描述 解題思路 關鍵代碼框架 難點分析 擴展方向 Python實例題 題目 基于聯邦學習的隱私保護 AI 系統&#xff08;分布式學習、隱私計算&#xff09; 問題描述 開發一個基于聯邦學習的隱私保護 AI 系統&#xff0c;包含以下功能&#xff…

點點(小紅書AI搜索):生活場景的智能搜索助手

1. 產品概述 點點是小紅書于2024年12月正式推出的AI搜索助手&#xff0c;由上海生動詩章科技有限公司開發&#xff0c;定位為生活場景搜索工具&#xff0c;聚焦交通、美食、旅游、購物等日常需求&#xff0c;旨在通過即時信息和真實用戶分享幫助用戶“精準避坑”。 核心特點 …

軟件工程概述:核心概念、模型與方法全解析

一、軟件工程定義與誕生背景 定義 將系統化、規范化、可度量的方法應用于軟件開發、運行和維護的過程&#xff08;IEEE標準&#xff09;。 核心目標&#xff1a;在可控成本下&#xff0c;生產高質量、可維護、滿足需求的軟件產品。 - 軟件開發&#xff1a;需求 → 設計 → 編碼…

LVS+Keepalived+nginx

LVSKeepalivednginx 1 安裝依賴 sudo yum install ipvsadm keepalived -y 查詢是否安裝成功 rpm -q -a keepalived 2 配置虛擬IP并安裝ipvsadm /etc/sysconfig/network-scripts cp ifcfg-ens33 ifcfg-ens33:1 修改里面配置文件 TYPE"Ethernet" PROXY_METHOD"n…

數據分析實操篇:京東淘寶商品實時數據獲取與分析

在電商行業蓬勃發展的當下&#xff0c;數據已然成為驅動決策的核心要素。無論是商家精準把控市場需求、制定營銷策略&#xff0c;還是消費者做出明智的購物抉擇&#xff0c;都離不開對電商平臺商品數據的深入剖析。京東和淘寶作為國內電商領域的兩大巨頭&#xff0c;匯聚了海量…

微信小程序掃碼添加音頻播放報錯{errCode:10001, errMsg:“errCode:602,err:error,not found param“}

主要流程代碼如下&#xff1a; let innerAudioContext wx.createInnerAudioContext() // 提示音 innerAudioContext.autoplay true innerAudioContext.src ../images/scan.mp3 innerAudioContext.onError(function(res){ console.log(onError 開始監聽:,res) }) innerAudi…

SVN合并指南,從dev合并部分revision到release指南

dev合并到release 1.進入release的工作區&#xff0c;右擊選擇Merge 點擊Next 2.確認merge來源分支和當前分支 點擊Show Log&#xff0c;挑選需要合并的單號 3. 選擇需要合并的commit 注意點擊Hide no-mergeable revisions&#xff0c;來隱藏掉已經合并的commit 4.選擇需…