日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

初识动态规划(一)简单入门动态规划与上手操作

發布時間:2024/3/13 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 初识动态规划(一)简单入门动态规划与上手操作 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

dp動態規劃

一、認識動態規劃

前言:近期我在慢慢刷動態規劃的題,雖然還是入門階段,但還是準備記錄我動態規劃前期是如何刷題過程

先根據一個例題來引入動態規劃——換零錢

  • 提出問題:要求使用1,5,11的鈔票面額進行換總金額為w的最小張數
  • 分析問題:在兌換的最終情況下(即換一最后一張面額的情況),要么是面額為1,要么5,要么11,所以
  • 我們可以得出:(f(w)表示換w金額需要的最少張數)

    • f(w) = f(w - 1) + 1; //該式子表示的是如果要得出f(w),就用前面已得出的f(w - 1) 加上一張面額為1的鈔票即可
    • f(w) = f(w - 5) + 1;//該式子表示的是如果要得出f(w),就用前面已得出的f(w - 5) 加上一張面額為5的鈔票即可
    • f(w) = f(w - 11) + 1;

    故我們可知,若是求最少換零錢的張數就是

    ? f(w - 1) & f(w - 5) & f(w - 11)

    ? 三個中最小的那一個

    ? 3. 給出具體例子

    那么,假如w=15的時候,同樣,鈔票面額分別為1511,我們該取那種鈔票呢?當然是各種方案中,cost值最低的那一個!-1:cost = f(14) + 1 = 4 + 1 = 5;-5:cost = f(10) + 1 = 2 + 1 = 3-11:cost = f(4) + 1 = 4 + 1 = 5;再次深度解釋一下:其中第二個取5的式子:f(10) = f(10 - 5) + 1 = 1 + 1; 即子問題的解;第三個取11的式子:f(4) = f(4 - 1) + 1 = 4;
  • 得出結論

    大致我們可以得出,我們所求的就是前面 當前最優值 = 前面最優值 + 1

    我們將求解f(w)就可以理解為求解多個子問題來達到求解f(w)

    這就是dp --> 動態規劃

  • 解決問題的特點
  • 能將問題拆成幾個問題,且滿足無后效性(即不管前面的過程,只需要得出前面的子最優解解即可)

  • 最優子結構性質,能夠由子問題推導出結果

  • 詳細來說:

    • 求最大最小值
      • 從左上角走到右下角路徑的最大數字和
      • 最長上升子序列
      • 最長等差序列
      • 最少換錢張數
    • 計數
      • 有多少種方式走到右下角
      • 有多少種方法選出k個數使得和是sum
      • 爬樓梯
    • 判斷
      • 是否存在先手贏,取石子游戲
  • 解題一般步驟
  • 判斷是否是最優問題,并存在子問題
  • 確定dp數組用一維或者更多,并且表示什么意思
  • 比如dp[i][j】,表示為從i下標到j下標長度的回文子串個數
  • 推導出dp狀態方程,和判斷條件
  • 確定好dp初始數組長度,和是否設立初始值
  • 選用合適的循環條件達到自己的目的
  • 二、下面進行具體刷動規的題型

    • 斐波那契數

    • 零錢兌換

    • 最長遞增子序列

    • 爬樓梯

  • 斐波那契數

    斐波那契數 (通常用 F(n) 表示)形成的序列稱為 斐波那契數列 。該數列由 0 和 1 開始,后面的每一項數字都是前面兩項數字的和。也就是:

    F(0) = 0,F(1) = 1
    F(n) = F(n - 1) + F(n - 2),其中 n > 1
    給定 n ,請計算 F(n) 。

    示例 1:

    輸入:n = 2
    輸出:1
    解釋:F(2) = F(1) + F(0) = 1 + 0 = 1
    示例 2:

    輸入:n = 3
    輸出:2
    解釋:F(3) = F(2) + F(1) = 1 + 1 = 2
    示例 3:

    輸入:n = 4
    輸出:3
    解釋:F(4) = F(3) + F(2) = 2 + 1 = 3

    來源:力扣(LeetCode)
    鏈接:https://leetcode.cn/problems/fibonacci-number
    著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。

    class Solution {public int fib(int n) {//動態規劃 dp[i] 表示的是第i個數表示的值if (n == 0) return 0; //處理特殊情況int []dp = new int[n + 1]; //數組長度初始化,一般情況下多一點dp[0] = 0; //初始化dp[1] = 1;for (int i = 2; i <= n; i++){ //循環過程dp[i] = dp[i - 1] + dp[i - 2]; //狀態方程}return dp[n]; //得到最終結果} }
  • 零錢兌換

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

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

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

    示例 1:

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

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

    輸入:coins = [1], amount = 0
    輸出:0

    來源:力扣(LeetCode)
    鏈接:https://leetcode.cn/problems/coin-change
    著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。

    class Solution {public int coinChange(int[] coins, int amount) {//動態規劃int[] dp = new int[amount+1];Arrays.fill(dp, amount+1);//base casedp[0] = 0;// 外層的for循環在遍歷時實現遍歷所有狀態的所有取值for(int i = 0; i < dp.length; i++){// 內層for循環求在所有選擇中的最小值for(int coin : coins){//子問題無解,跳過if(i - coin < 0){continue;}//狀態轉移dp[i] = Math.min(dp[i],1+dp[i-coin]);}}//查看金額能不能算出來return (dp[amount] == amount+1 ? -1 : dp[amount]);//暴力遞歸——超時// if (amount == 0){// return 0;// }// if (amount < 0){// return -1;// }// int min = Integer.MAX_VALUE;// for (int i = 0; i < coins.length; i++){// int temp = coinChange(coins, amount - coins[i]);// if (temp == -1){continue;}// min = Math.min(min, temp + 1);// }// return min == Integer.MAX_VALUE ? -1 : min;} }
  • 最長遞增子序列

    給你一個整數數組 nums ,找到其中最長嚴格遞增子序列的長度。

    子序列 是由數組派生而來的序列,刪除(或不刪除)數組中的元素而不改變其余元素的順序。例如,[3,6,2,7] 是數組 [0,3,1,6,2,2,7] 的子序列。

    示例 1:

    輸入:nums = [10,9,2,5,3,7,101,18]
    輸出:4
    解釋:最長遞增子序列是 [2,3,7,101],因此長度為 4 。
    示例 2:

    輸入:nums = [0,1,0,3,2,3]
    輸出:4
    示例 3:

    輸入:nums = [7,7,7,7,7,7,7]
    輸出:1

    來源:力扣(LeetCode)
    鏈接:https://leetcode.cn/problems/longest-increasing-subsequence
    著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。

    class Solution {public int lengthOfLIS(int[] nums) {//動態規劃if (nums == null || nums.length == 0){return 0;}//求最優解,利用dp,輸出為長度,故new一維dp數組,dp[i]初始為1,狀態為nums[i]和nums[j]大小比較,更新狀態值//dp[i]表示的是長度為i + 1的數組最大遞增子序列int len = nums.length;int result = 1;int []dp = new int[len + 1];Arrays.fill(dp, 1); //填充dp數組,全部為1for (int i = 1; i < len; i++){for (int j = 0; j < i; j++){if (nums[j] < nums[i]){ //判斷條件dp[i] = Math.max(dp[i], dp[j] + 1); //狀態轉移}result = Math.max(dp[i], result); //由于有子問題最大值,故設立變量result更新最大值}}return result; //輸出dp[len - 1]為長度為len - 1的數組最大遞增子序長度} }
  • 爬樓梯
  • 假設你正在爬樓梯。需要 n 階你才能到達樓頂。

    每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢?

    示例 1:

    輸入:n = 2
    輸出:2
    解釋:有兩種方法可以爬到樓頂。

  • 1 階 + 1 階
  • 2 階
    示例 2:
  • 輸入:n = 3
    輸出:3
    解釋:有三種方法可以爬到樓頂。

  • 1 階 + 1 階 + 1 階
  • 1 階 + 2 階
  • 2 階 + 1 階
  • 來源:力扣(LeetCode)
    鏈接:https://leetcode.cn/problems/climbing-stairs
    著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。

    class Solution {public int climbStairs(int n) {//dp[i] 表示的是爬到第i階方法數int []dp = new int[n + 1];dp[0] = 1; //初始化dp[0]為1——>以至于后面for循環dp[2]能夠得出正確答案,只要1和2是正確答案,后面可得正確取值dp[1] = 1; for (int i = 2; i <= n; i++){dp[i] = dp[i - 1] + dp[i - 2]; //分為1步和2步兩種情況,并且求種數,為兩者之和}return dp[n];} }

    總結:看完這幾道例題,大家也許會發現主要還是dp一維數組,并且算是比較簡單的,但是對于剛開始入門動規的話,應該能夠起到一定的作用,力扣上面也有一個動態規劃計劃集,我暫時也是根據上面做的。大家有興趣可以去跟著做一做。如有不足,請與我聯系更改。

    我把鏈接放在這里,大家有興趣可以試試:力扣-動態規劃入門

    總結

    以上是生活随笔為你收集整理的初识动态规划(一)简单入门动态规划与上手操作的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。