算法學習 —— 動態規劃練習(一)

1、買賣股票的最佳時機(LeetCode-121)

1.1 題目介紹

121. 買賣股票的最佳時機java

給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。

若是你最多隻容許完成一筆交易(即買入和賣出一支股票),設計一個算法來計算你所能獲取的最大利潤。

注意你不能在買入股票前賣出股票。

示例 1:

輸入: [7,1,5,3,6,4]
輸出: 5
解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 5 天(股票價格 = 6)的時候賣出,最大利潤 = 6-1 = 5 。
     注意利潤不能是 7-1 = 6, 由於賣出價格須要大於買入價格。
示例 2:

輸入: [7,6,4,3,1]
輸出: 0
解釋: 在這種狀況下, 沒有交易完成, 因此最大利潤爲 0。

1.2 解題思路

想要利潤最大,儘量地要保證購買的時候價格最低,總利潤最高。由此能夠列出狀態轉移方程。算法

buy = min{buy,price} profilt = max{profilt,price-buy}數組

1.3 解法

public int maxProfit(int[] prices) {
        int profilt = 0;
        int buy = Integer.MAX_VALUE;
        for (int price : prices) {
            buy = Math.min(buy, price);
            profilt = Math.max(profilt, price - buy);
        }
        return profilt;
    }

2、使用最小花費爬樓梯(LeetCode-746)

2.1 題目介紹

數組的每一個索引作爲一個階梯,第 i個階梯對應着一個非負數的體力花費值 costispa

每當你爬上一個階梯你都要花費對應的體力花費值,而後你能夠選擇繼續爬一個階梯或者爬兩個階梯。.net

您須要找到達到樓層頂部的最低花費。在開始時,你能夠選擇從索引爲 0 或 1 的元素做爲初始階梯。設計

示例 1: 輸入: cost = [10, 15, 20] 輸出: 15 解釋: 最低花費是從cost[1]開始,而後走兩步便可到階梯頂,一共花費15。code

示例 2: 輸入: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] 輸出: 6 解釋: 最低花費方式是從cost[0]開始,逐個通過那些1,跳過cost[3],一共花費6。 注意: cost 的長度將會在 [2, 1000]。 每個 cost[i] 將會是一個Integer類型,範圍爲 [0, 999]。blog

2.2 解題思路

以樣本爲例cost = [10, 15, 20] n = 3;索引

最後一步: 根據題意咱們知道,最後一步不必定是cost[2](即20),還有多是以後的值,咱們這裏假設有cost[3]且cost[3] = 0,這裏咱們就統一認爲最後一步是cost[3],由於它的須要用的體力值設置爲0。因此最後走到cost[2]所用的整體力值,和走到cost[3]的是同樣的。leetcode

子問題 最後一步消耗的體力值是cost[3],總共消耗的體力值爲f[3]。 走到了最後一步以後,往前回退,所面對的選擇是,要麼是倒退一步,要麼是倒退兩步。

因而有了子問題方程:

f[3] = min(f[1],f[2])+cost[3]

狀態轉移方程

f[x] = min(f[x-1],f[x-2])+cost[x]

初始條件 第一步能夠從cost[0]開始走,也能夠從cost[1]開始走。因而有了 f[0] = cost[0] f[1] = cost[1]

邊界 int costLength = cost.length; cost[costLengh+1] = 0 f[costLengh+1]爲最終的解。

2.3 解法

public int minCostClimbingStairs(int[] cost) {

        int n = cost.length;
        int[] f = new int[n+1];
        //初始化
        f[0] = cost[0];
        f[1] = cost[1];
        for (int i = 2; i <= n; i++) {
            int tempCost = 0;
            if (i == n) {
            	//cost[n] = 0
                tempCost = 0;
            } else {
                tempCost = cost[i];
            }
            f[i] = Math.min(f[i - 1], f[i - 2]) + tempCost;
        }
        return f[n];
    }

3、爬樓梯(LeetCode-70)

3.1 題目介紹

70. 爬樓梯

假設你正在爬樓梯。須要 n 階你才能到達樓頂。

每次你能夠爬 1 或 2 個臺階。你有多少種不一樣的方法能夠爬到樓頂呢? 注意:給定 n 是一個正整數。

示例 1: 輸入: 2 輸出: 2 解釋: 有兩種方法能夠爬到樓頂。

  1. 1 階 + 1 階
  2. 2 階

示例 2: 輸入: 3 輸出: 3 解釋: 有三種方法能夠爬到樓頂。

  1. 1 階 + 1 階 + 1 階
  2. 1 階 + 2 階
  3. 2 階 + 1 階

3.2 解題思路

最後一步:

最後一步是第n個臺階,咱們這邊假設爲4。

子問題 最後一步到第4個臺階,假設總共有走法f[4]。 若是是走到第3個臺階的話,就只能再走1步 若是走到第2個臺階的話,能夠走2步,或者走2次,分別走1步。

因而有了子問題方程:

f[4] = f[4-step1] + f[4-step2] f[4] = f[3] + f[2]

狀態轉移方程

f[x] = f[x-1] + f[x-2]

3.3 解法

class Solution {
    public int climbStairs(int n) {
        int[] f = new int[n+1];
        if(n<=2){
            return n;
        }
        //初始化
        f[0] = 0;
        f[1] = 1;
        f[2] = 2;
        //f[x] = f[x-1] + f[x-2]
        for(int i=3;i<=n;i++){
            f[i] = f[i-1]+f[i-2];
        }
        return f[n];
        
    }
}

4、最大子序和(LeetCode-53)

4.1 題目介紹

給定一個整數數組 nums ,找到一個具備最大和的連續子數組(子數組最少包含一個元素),返回其最大和。

示例: 輸入: [-2,1,-3,4,-1,2,1,-5,4], 輸出: 6 解釋: 連續子數組 [4,-1,2,1] 的和最大,爲 6。 進階:

若是你已經實現複雜度爲 O(n) 的解法,嘗試使用更爲精妙的分治法求解。

4.2 解題思路

分析能不能使用DP,要考慮符不符合DP的子問題重疊,即一個子問題,依賴於上一個子問題

簡化輸入,只有-2,則dp[0] 爲最大子序列和,dp[0] = -2,

假設只有,-2,1,則dp[1]會參考dp[0],會比較1與-2+1的大小,從而肯定要不要前面的-2,由此可得出

$dp[i] = \max\{ dp[i-1]+nums[i],nums[i]\} $

4.3 解法

public static int maxSubArray(int[] nums) {
        // dp[i] = max(dp[i-1]+nums[i],nums[i])
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        int res = dp[0];
        for (int i = 1; i < nums.length; i++) {
            dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
            res = res > dp[i] ? res : dp[i];
        }
        return res;
    }

參考文檔

LeetCode中動態規劃題解合集

相關文章
相關標籤/搜索