從0開始掌握動態規劃

動態規劃的核心思想 -- 以空間換時間

復雜點說通過分解問題為子問題并存儲子問題解來優化復雜計算的算法策略。

簡單看個問題。

一,初始:求最長連續遞增子序列

nums = [10,9,2,5,3,7,101,18]

求上面數組中的最長連續遞增子序列,輸出其長度

暴力解法中我們需要以每個數為開頭去遍歷數組,得到最長的子數組。

會產生如下遍歷

3,7,101

7,101

可以看到,有重復的計算。我們先用java寫一下暴力解法。

暴力解法
    public int lengthOfLIS(int[] nums) {if (nums == null || nums.length == 0) {return 0;}int res = 0;for (int i = 0; i < nums.length; i++) {int temp = 1; // 當前子序列的長度,初始為1(單個元素)for (int j = i + 1; j < nums.length; j++) {if (nums[j] > nums[j - 1]) {temp++;} else {break;}}res = Math.max(res, temp); // 更新最長子序列的長度}return res;}

雙重for循環,時間復雜度為 (O(n^2)),空間復雜度為 (O(1))。

動態規劃

初始化dp的int數組。值為到當前位置的最大連續數。這樣整個遍歷完dp數組的值應該是

[1,1,1,2,1,2,3,1]。 可以看到最大長度為3。

    /*** 方法二: 動態規劃求解連續遞增子序列* @param nums* @return*/public int lengthOfLIS2(int[] nums) {if (nums == null || nums.length == 0) {return 0;}int n = nums.length;int[] dp = new int[n];dp[0] = 1; // 單個元素本身就是一個長度為 1 的連續遞增子序列int res = 1; // 初始化結果為 1for (int i = 1; i < n; i++) {if (nums[i] > nums[i - 1]) {dp[i] = dp[i - 1] + 1;} else {dp[i] = 1; // 當前元素本身可以作為一個新的連續遞增子序列的起點}res = Math.max(res, dp[i]); // 更新最長子序列的長度}return res;}

時間復雜度:(O(n))
空間復雜度:(O(n))

二,升級:求最長遞增子序列

nums = [10,9,2,5,3,7,101,18]

求上面數組中的最長遞增子序列,輸出其長度

將上面一道題進行稍微變化一下,我們可以看出,現在的結果應該是2,3,7,101。輸出結果應該是4。

如果不用動態規劃,這道題有點難解。需要用到回溯+記憶,單純的暴力解法并不適用。

比如我再加一個測試用例

nums?=[0,1,0,3,2,3]

?回溯法
    /*** 方法一: 暴力解法* @param nums* @return*/public int lengthOfLIS(int[] nums) {if (nums == null || nums.length == 0) return 0;int maxLen = 0;for (int i = 0; i < nums.length; i++) {maxLen = Math.max(maxLen, backtrack(nums, i, new ArrayList<>()));}return maxLen;}// 回溯法生成所有遞增子序列private int backtrack(int[] nums, int index, List<Integer> current) {if (index >= nums.length) return current.size();int maxLen = current.size();  // 不選當前元素的默認長度// 選擇當前元素的情況if (current.isEmpty() || nums[index] > current.get(current.size() - 1)) {current.add(nums[index]);int lenWith = backtrack(nums, index + 1, current);current.remove(current.size() - 1);maxLen = Math.max(maxLen, lenWith);}// 不選當前元素的情況int lenWithout = backtrack(nums, index + 1, current);return Math.max(maxLen, lenWithout);}

時間復雜度: (O(2^n))

空間復雜度:O(n)

該方法容易超過時間限制

動態規劃

這個就需要在上個動態規劃樣例中稍微改動一下。

我們先模擬一下對照樣例生成的dp數組應該的樣子。

int[] nums = {10, 9, 2,  5, 3, 7, 101, 18};
int[] dp =   {1,  1, 1,  2, 2, 3,  4,  4};

先舉個簡單的方便觀察的例子

int[] nums = {1, 2, 3, 4, 2, 6, 7};
int[] dp =   {1, 2, 3, 4, 1, 5, 6};

即便當數組為遞減數組時,長度也會輸出1

  1. 所以我們還是需要先將dp數組全部初始化1
  2. 第一次遍歷,2 > 1的,所以dp[1] = dp[0] + 1;
  3. 第二次遍歷,3 > 1的,所以dp[2] = dp[0] + 1; 然后 3 > 2的,所以?dp[2] = dp[1] + 1;
  4. ……
  5. 第五次遍歷,6 > 4的,所以dp[5] = dp[3] + 1;但是6 > 2,不能得出dp[5] = dp[4] + 1,需要dp[4] + 1與當前的dp[5]的值進行比較。取最大的一個。
  6. ……

所以綜上我們可以寫出代碼

    /*** 方法二: 動態規劃求解遞增子序列* @param nums* @return*/public int lengthOfLIS2(int[] nums) {if (nums == null || nums.length == 0) {return 0;}int n = nums.length;int[] dp = new int[n];Arrays.fill(dp, 1);int res = 1; // 初始化結果為 1for (int i = 1; i < n; i++) {for (int j = 0; j < i; j++) {if (nums[j] < nums[i]) {dp[i] = Math.max(dp[i], dp[j] + 1);}res = Math.max(res, dp[i]);}}return res;}

?時間復雜度為 ?O(n2),空間復雜度為 ?O(n)。

三,再升級:刪除最少元素,使剩余元素先遞增后遞減

動態規劃

還是以剛剛的例子為例

nums = [10,9,2,5,3,7,101,18]

刪除最少元素,使剩余元素先遞增后遞減,輸出最少需要刪除多少元素。

?通過上面兩個例子,我們可以看出一個dp數組只能保存一個狀態。

對于這道題,我們可以考慮使用兩個dp數組來完成。

nums = [10,9,2,5,3,7,101,18]
int[] dp1 =   {1,  1, 1,  2, 2, 3,  4,  4}; //遞增dp
int[] dp2 =   {4,  3, 1,  2, 1, 1,  2,  1}; //遞減dp

?可以看出在dp1[6] + dp2[6] = 6的時候是最大的,所以最大長度應該是dp1[6] + dp2[6] - 1 = 5;

因為6這個節點重復計算了,所以需要減1

那么就能得出答案需要刪除:nums.length() - 5 = 3;

最少需要刪除3個元素。

    /*** 方法二: 動態規劃求解刪除最少元素,使剩余元素先遞增后遞減* @param nums* @return*/public int lengthOfLIS3(int[] nums) {if (nums == null || nums.length == 0) {return 0;}int n = nums.length;int[] dp1 = new int[n];int[] dp2 = new int[n];Arrays.fill(dp1, 1);Arrays.fill(dp2, 1);// 遞增子序列for (int i = 1; i < n; i++) {for (int j = 0; j < i; j++) {if (nums[j] < nums[i]) {dp1[i] = Math.max(dp1[i], dp1[j] + 1);}}}// 遞減子序列for (int i = n - 2; i >= 0; i--) {for (int j = n - 1; j > i; j--) {if (nums[j] < nums[i]) {dp2[i] = Math.max(dp2[i], dp2[j] + 1);}}}// 合并int max = 0;for (int i = 0; i < n; i++) {if (dp1[i] + dp2[i] > max) {max = dp1[i] + dp2[i];}}return n - max - 1;}

?四,看一道力扣原題

322. 零錢兌換

?這道題可以換個角度看看,我們要求amount的最小硬幣個數。可以構建dp[amount + 1]數組,

求從1 - amount間的所有最小個數。

換個簡單的實例

輸入:coins = [1, 2], amount = 5

以外層coins為循環,內層循環amount得到最小值

如上面例子。

初始化dp數組,因為要求最小,所以初始值應該為最大,且dp[0] = 0;

第一次外層循環1得到dp數組[0,1,2,3,4,5]

第二次外層循環2得到dp數組[0,1,1,2,2,3]

構建dp公式:

dp[i] = Math.min(dp[i], dp[i - coin] + 1);

?得到解法

    public int coinChange(int[] coins, int amount) {int[] dp = new int[amount + 1];Arrays.fill(dp, amount + 1); // 初始化為不可達標記dp[0] = 0; // 基礎情況// 外層循環遍歷硬幣for (int coin : coins) {// 內層循環遍歷金額(完全背包正序遍歷)for (int i = coin; i <= amount; i++) {dp[i] = Math.min(dp[i], dp[i - coin] + 1);}}return dp[amount] > amount ? -1 : dp[amount];}

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

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

相關文章

Python Requests 庫:從安裝到精通

摘要 本文詳細介紹 Python Requests 庫的安裝與使用&#xff0c;通過常見示例讓你輕松掌握。 一、引言 在當今的互聯網時代&#xff0c;與各種 Web 服務進行交互是非常常見的需求。Python 作為一門功能強大且易于學習的編程語言&#xff0c;提供了許多用于網絡請求的庫&…

Manus技術架構、實現內幕及分布式智能體項目實戰

Manus技術架構、實現內幕及分布式智能體項目實戰 模塊一&#xff1a; 剖析Manus分布式多智能體全生命周期、九大核心模塊及MCP協議&#xff0c;構建低幻覺、高效且具備動態失敗處理能力的Manus系統。 模塊二&#xff1a; 解析Manus大模型Agent操作電腦的原理與關鍵API&#xf…

C算術運算符 printf輸出格式 字符指針打印輸出 使用scanf函數進行輸入

一 算術運算符 加, 一元取正 - 減, 一元取負 * 乘 / 除 % 求余 -- 自減1 自加1 邏輯運算符 && 邏輯與 || 邏輯或 ! 邏輯非 關系運算符 > 大于 > 大于等于 < 小于 < 小于等于 等于 ! 不等于 位運算符號 & 按位與 | 按位或 ^ 按位異或…

STM32中Hz和時間的轉換

目錄 一、常見的頻率單位及其轉換 二、計算公式 三、STM32中定時器的應用 四、例子 一、常見的頻率單位及其轉換 赫茲&#xff08;Hz&#xff09;是頻率的國際單位&#xff0c;表示每秒鐘周期性事件發生的次數。 1 kHz&#xff08;千赫茲&#xff09; 1,000 Hz1 MHz&#…

《分布式軟總線:不同頻段Wi-Fi環境下設備發現兼容性難題》

分布式軟總線技術作為實現設備互聯互通的關鍵&#xff0c;正逐漸成為構建萬物互聯世界的基石。然而&#xff0c;當分布式軟總線面臨不同頻段Wi-Fi環境時&#xff0c;設備發現的兼容性問題成為了阻礙其廣泛應用的一大挑戰。這一問題不僅影響著用戶體驗&#xff0c;也制約著分布式…

MCP(Model Context Protocol 模型上下文協議)科普

MCP&#xff08;Model Context Protocol&#xff0c;模型上下文協議&#xff09;是由人工智能公司 Anthropic 于 2024年11月 推出的開放標準協議&#xff0c;旨在為大型語言模型&#xff08;LLM&#xff09;與外部數據源、工具及服務提供標準化連接&#xff0c;從而提升AI在實際…

【mongodb】數據庫操作

目錄 1. 查看所有數據庫2. 切換到指定數據庫&#xff08;若數據庫不存在&#xff0c;則創建&#xff09;3. 查看當前使用的數據庫4. 刪除當前數據庫5.默認數據庫 1. 查看所有數據庫 1.show dbs2.show databases 2. 切換到指定數據庫&#xff08;若數據庫不存在&#xff0c;則…

ICPR-2025 | 讓機器人在未知環境中 “聽懂” 指令精準導航!VLTNet:基于視覺語言推理的零樣本目標導航

作者&#xff1a;Congcong Wen, Yisiyuan Huang, Hao Huang ,Yanjia Huang, Shuaihang Yuan, YuHao, HuiLin and Yi Fang 單位&#xff1a;紐約大學阿布扎比分校具身人工智能與機器人實驗室&#xff0c;紐約大學阿布扎比分校人工智能與機器人中心&#xff0c;紐約大學坦登工程…

基于DeepSeek的考研暑假日志分析

注&#xff1a;我去年考研時寫了日志&#xff0c;大致記錄了我每天的主要活動。由于過于瑣碎&#xff0c;一直沒有翻看。突發奇想&#xff0c;現在利用deepseek總結其中規律。 從你的日志中可以總結出以下規律和活動興衰起落&#xff1a; ??一、學習活動規律與演變?? ??…

【刷題Day20】TCP和UDP

TCP 和 UDP 有什么區別&#xff1f; TCP提供了可靠、面向連接的傳輸&#xff0c;適用于需要數據完整性和順序的場景。 UDP提供了更輕量、面向報文的傳輸&#xff0c;適用于實時性要求高的場景。 特性TCPUDP連接方式面向連接無連接可靠性提供可靠性&#xff0c;保證數據按順序…

REST 架構詳解:從概念到應用的全面剖析

REST&#xff08;Representational State Transfer&#xff09;即表述性狀態轉移&#xff0c;是一種用于構建網絡應用程序的架構風格和設計理念&#xff0c;由計算機科學家羅伊?菲爾丁&#xff08;Roy Fielding&#xff09;在 2000 年提出。以下是關于它的詳細介紹&#xff1a…

藍橋杯之遞歸二

1.數的劃分 題目描述 將整數 nn 分成 kk 份&#xff0c;且每份不能為空&#xff0c;任意兩份不能相同(不考慮順序)。 例如&#xff1a;n7&#xff0c;k3n7&#xff0c;k3&#xff0c;下面三種分法被認為是相同的。 1&#xff0c;1&#xff0c;5;1&#xff0c;5&#xff0c;…

LeetCode(Hot.2)—— 49.字符異位詞分組題解

Problem: 49. 字母異位詞分組 字母異位詞的定義是&#xff1a;兩個單詞的字母組成一樣&#xff0c;但順序可以不同&#xff0c;比如 eat、tea 和 ate 就是一個組的。 思路 將每個字符串按字母排序&#xff0c;把排序后的字符串作為 key&#xff0c;相同 key 的放在一個 list 中…

為什么信號完整性對于高速連接器設計至關重要?

外部連接器通過在各種電子元件和系統之間可靠地傳輸數據而不損失保真度來保持信號完整性。在本文中&#xff0c;我們將討論信號完整性的重要性&#xff0c;回顧高速部署挑戰&#xff0c;并重點介紹各種連接器設計策略&#xff0c;以防止失真和降級。 了解連接器信號完整性挑戰…

得物官網sign簽名逆向分析

打開得物官網&#xff0c;點擊鞋類&#xff0c;可以看到請求 直接搜sign function p(e) {return f()("".concat(e ? s()(e).sort().reduce(function(t, n) {return "".concat(t).concat(n).concat(e[n])}, "") : "", "048a9…

Ubuntu 安裝WPS Office

文章目錄 Ubuntu 安裝WPS Office下載安裝文件安裝WPS問題1.下載缺失字體文件2.安裝缺失字體 Ubuntu 安裝WPS Office 下載安裝文件 需要到 WPS官網 下載最新軟件&#xff0c;比如wps-office_12.1.0.17900_amd64.deb 安裝WPS 執行命令進行安裝 sudo dpkg -i wps-office_12.1…

javaSE.判空包裝類

判空包裝類Optional&#xff0c;這個類可以很有效的處理空指針問題 空指針異常&#x1f447; 特判null&#x1f447; Optional類可以更加優雅地處理這種問題&#x1f447;&#x1f447; ofNullable&#x1f447; isPresent isEmpty &#x1f447; &#x1f447; 包裝之后&…

使用 vcpkg 構建支持 HTTPS 的 libcurl 并解決常見鏈接錯誤

適用環境&#xff1a;Windows 10/11 Visual Studio 2022 CMake ≥ 3.20 目標讀者&#xff1a;希望在 C 項目中輕松調用 HTTPS&#xff08;GET/POST/PUT/DELETE&#xff09;&#xff0c;又被 LNK20xx 鏈接錯誤困擾的開發者 目錄 為什么選 vcpkg 與 libcurl用 vcpkg 安裝帶 SS…

ISO26262-淺談用例導出方法和測試方法

目錄 1 摘要2 測試方法3 測試用例導出方法4 測試方法與用例導出方法的差異和聯系5 結論 1 摘要 ISO26262定義了測試方法和用例導出方法&#xff0c;共同保證產品的開發質量。但在剛開始學習ISO26262的時候&#xff0c;又不是非常清晰地理解它倆的區別和聯系。本文主要對它倆的…

RoBoflow數據集的介紹

https://public.roboflow.com/object-detection&#xff08;該數據集的網址&#xff09; 可以看到一些基本情況 如果我們想要下載&#xff0c;直接點擊 點擊圖像可以看到一些基本情況 可以點擊紅色箭頭所指&#xff0c;右邊是可供選擇的一些yolo模型的格式 如果你想下載…