刷題85—動態規劃(二)— 股票6道

125.最佳買賣股票時機含冷凍期

題目鏈接
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown

題目描述
給定一個整數數組,其中第 i 個元素代表了第 i 天的股票價格 。​

設計一個算法計算出最大利潤。在滿足以下約束條件下,你可以儘可能地完成更多的交易(多次買賣一支股票):

你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。
賣出股票後,你無法在第二天買入股票 (即冷凍期爲 1 天)。
示例:

輸入: [1,2,3,0,2]
輸出: 3
解釋: 對應的交易狀態爲: [買入, 賣出, 冷凍期, 買入, 賣出]

題目分析

  1. 使用二維數組dp來定義當前股票的日期和狀態:dp[i][0]:第i天手裏沒有股票,dp[i][1]:第i天手裏有股票;
  2. dp[i][0]的上一個狀態是:dp[i-1][0]無操作和dp[i-1][1]賣出股票,即dp[i-1][1] + prices[i];
  3. dp[i][1]的上一個狀態是:dp[i-1][1]無操作和dp[i-2][0]買入股票,即dp[i-2][0] - prices[i](由於有一天的冷凍期,所以是i-2);
  4. 狀態轉移方程:dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i]);dp[i][1] = Math.max(dp[i-1][1],dp[i-2][0] - prices[i]);
  5. 判斷邊界值:i-1==-1時, dp[i][0] = 0,dp[i][1] = -prices[i]; i-2==-1時, dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i]); dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] - prices[i]);
/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
    let len = prices.length;
    if(len == 0) return 0;
    let dp = new Array(len).fill(0).map(() => new Array(2).fill(0));
    for(let i=0; i<len; i++){
        if(i-1 == -1){
            dp[i][0] = 0;
            dp[i][1] = -prices[i];
            continue;
        }else if(i-2 == -1){
            dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i]);
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] - prices[i]);
            continue;
        }
        dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i]);
        dp[i][1] = Math.max(dp[i-1][1],dp[i-2][0] - prices[i]);
         
    }
    return dp[len-1][0];
};

126.買賣股票的最佳時機 II

題目鏈接
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii

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

設計一個算法來計算你所能獲取的最大利潤。你可以儘可能地完成更多的交易(多次買賣一支股票)。

注意:你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。

示例 1:

輸入: [7,1,5,3,6,4]
輸出: 7
解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 3 天(股票價格 = 5)的時候賣出, 這筆交易所能獲得利潤 = 5-1 = 4 。
隨後,在第 4 天(股票價格 = 3)的時候買入,在第 5 天(股票價格 = 6)的時候賣出, 這筆交易所能獲得利潤 = 6-3 = 3 。
示例 2:

輸入: [1,2,3,4,5]
輸出: 4
解釋: 在第 1 天(股票價格 = 1)的時候買入,在第 5 天 (股票價格 = 5)的時候賣出, 這筆交易所能獲得利潤 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接連購買股票,之後再將它們賣出。
因爲這樣屬於同時參與了多筆交易,你必須在再次購買前出售掉之前的股票。
示例 3:

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

提示:

1 <= prices.length <= 3 * 10 ^ 4
0 <= prices[i] <= 10 ^ 4

題目分析

  1. 使用二維數組dp來定義當前股票的日期和狀態:dp[i][0]:第i天手裏沒有股票,dp[i][1]:第i天手裏有股票;
  2. dp[i][0]的上一個狀態是:dp[i-1][0]無操作和dp[i-1][1]賣出股票,即dp[i-1][1] + prices[i];
  3. dp[i][1]的上一個狀態是:dp[i-1][1]無操作和dp[i-1][0]買入股票,即dp[i-1][0] - prices[i];
  4. 狀態轉移方程:dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i]);dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] - prices[i]);
  5. 判斷邊界值:i-1==-1時, dp[i][0] = 0,dp[i][1] = -prices[i];
/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
    let len = prices.length;
    let dp = new Array(len).fill(0).map(() => new Array(2).fill(0));
    for(let i=0; i<len; i++){
        if(i-1 == -1){
            dp[0][0] = 0;
            dp[0][1] = -prices[i];
            continue;
        }
        dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i]);
        dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i]);
    }
    return dp[len-1][0];
};

127.買賣股票的最佳時機 III

題目鏈接
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。

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

設計一個算法來計算你所能獲取的最大利潤。你最多可以完成 兩筆 交易。

注意: 你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。

示例 1:

輸入: [3,3,5,0,0,3,1,4]
輸出: 6
解釋: 在第 4 天(股票價格 = 0)的時候買入,在第 6 天(股票價格 = 3)的時候賣出,這筆交易所能獲得利潤 = 3-0 = 3 。
隨後,在第 7 天(股票價格 = 1)的時候買入,在第 8 天 (股票價格 = 4)的時候賣出,這筆交易所能獲得利潤 = 4-1 = 3 。
示例 2:

輸入: [1,2,3,4,5]
輸出: 4
解釋: 在第 1 天(股票價格 = 1)的時候買入,在第 5 天 (股票價格 = 5)的時候賣出, 這筆交易所能獲得利潤 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接連購買股票,之後再將它們賣出。
因爲這樣屬於同時參與了多筆交易,你必須在再次購買前出售掉之前的股票。
示例 3:

輸入: [7,6,4,3,1]
輸出: 0
解釋: 在這個情況下, 沒有交易完成, 所以最大利潤爲 0。

題目分析

  1. 使用三維數組dp來定義當前股票的日期、交易次數、狀態:dp[i][k][0]:到第i天爲止,共交易了k次手裏沒有股票,dp[i][k][1]:到第i天爲止,共交易了k次手裏有股票;
  2. dp[i][k][0]的上一個狀態是:dp[i-1][k][0]無操作和dp[i-1][1]賣出股票,即dp[i-1][k][1] + prices[i];
  3. dp[i][k][1]的上一個狀態是:dp[i-1][k][1]無操作和dp[i-1][0]買入股票,即dp[i-1][k-1][0] - prices[i];
  4. 狀態轉移方程:dp[i][k][0] = Math.max(dp[i-1][k][0], dp[i-1][k][1] + prices[i]);dp[i][k][1] = Math.max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]);
  5. 判斷邊界值:i-1==-1時, dp[i][0] = 0,dp[i][1] = -prices[i];
/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
    let len = prices.length;
    if(len == 0) return 0;
    let dp = new Array(len).fill(0).map(() => new Array(3).fill(0));
    for(let i=0; i<len; i++){
        for(let j=0; j<=2; j++){
            dp[i][j] = new Array(2).fill(0);
        }
    }
    for(let i=0; i<len; i++){
        for(let k=2; k>=1; k--){
            if(i-1 == -1){
                dp[0][k][0] = 0;
                dp[0][k][1] = -prices[i];
                continue;
            }
            dp[i][k][0] = Math.max(dp[i-1][k][0], dp[i-1][k][1] + prices[i]);
            dp[i][k][1] = Math.max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]);
        }
    }
    return dp[len-1][2][0];
};

128.買賣股票的最佳時機 IV

題目鏈接
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。

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

設計一個算法來計算你所能獲取的最大利潤。你最多可以完成 k 筆交易。

注意: 你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。

示例 1:

輸入: [2,4,1], k = 2
輸出: 2
解釋: 在第 1 天 (股票價格 = 2) 的時候買入,在第 2 天 (股票價格 = 4) 的時候賣出,這筆交易所能獲得利潤 = 4-2 = 2 。
示例 2:

輸入: [3,2,6,5,0,3], k = 2
輸出: 7
解釋: 在第 2 天 (股票價格 = 2) 的時候買入,在第 3 天 (股票價格 = 6) 的時候賣出, 這筆交易所能獲得利潤 = 6-2 = 4 。
隨後,在第 5 天 (股票價格 = 0) 的時候買入,在第 6 天 (股票價格 = 3) 的時候賣出, 這筆交易所能獲得利潤 = 3-0 = 3 。

題目分析

  1. 判斷k是否超過len/2;
  2. 如果超過,就相當於k不受限制,可以忽略k;使用二維數組dp來定義當前股票的日期和狀態:dp[i][0]:第i天手裏沒有股票,dp[i][1]:第i天手裏有股票;
  3. dp[i][0]的上一個狀態是:dp[i-1][0]無操作和dp[i-1][1]賣出股票,即dp[i-1][1] + prices[i];
  4. dp[i][1]的上一個狀態是:dp[i-1][1]無操作和dp[i-1][0]買入股票,即dp[i-1][0] - prices[i];
  5. 狀態轉移方程:dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i]);dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] - prices[i]);
  6. 判斷邊界值:i-1==-1時, dp[i][0] = 0,dp[i][1] = -prices[i];
  7. 如果k沒超過,使用三維數組dp來定義當前股票的日期、交易次數、狀態:dp[i][k][0]:到第i天爲止,共交易了k次手裏沒有股票,dp[i][k][1]:到第i天爲止,共交易了k次手裏有股票;
  8. dp[i][k][0]的上一個狀態是:dp[i-1][k][0]無操作和dp[i-1][1]賣出股票,即dp[i-1][k][1] + prices[i];
  9. dp[i][k][1]的上一個狀態是:dp[i-1][k][1]無操作和dp[i-1][0]買入股票,即dp[i-1][k-1][0] - prices[i];
  10. 狀態轉移方程:dp[i][k][0] = Math.max(dp[i-1][k][0], dp[i-1][k][1] + prices[i]);dp[i][k][1] = Math.max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]);
  11. 判斷邊界值:i-1==-1時, dp[i][0] = 0,dp[i][1] = -prices[i];
/**
 * @param {number} k
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(k, prices) {
    let len = prices.length;
    if(len == 0 ){
        return 0;
    }
    if(k > len/2){
        let dp = new Array(len+1).fill(0).map(() => new Array(2).fill(0));
        for(let i=0; i<len; i++){
            if(i-1 == -1){
                dp[0][0] = 0;
                dp[0][1] = -prices[0];
                continue;
            }
            dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i]);
            dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i]);
        }
        return dp[len-1][0];
    }
    else{
        let dp = new Array(len+1).fill(0).map(() => new Array(k+1).fill(0));
        for(let i=0; i<len; i++){
            for(let j=0; j<=k; j++){
                dp[i][j] = new Array(2).fill(0);
            }
        }
        for(let i=0; i<len; i++){
            for(let j=k; j>=1; j--){
                if(i-1 == -1){
                    dp[0][j][0] = 0;
                    dp[0][j][1] = -prices[i];
                    continue;
                }
                dp[i][j][0] = Math.max(dp[i-1][j][0], dp[i-1][j][1] + prices[i]);
                dp[i][j][1] = Math.max(dp[i-1][j][1], dp[i-1][j-1][0] - prices[i]);
            }
        }
        return dp[len-1][k][0];
    }
};
  

129.買賣股票的最佳時機含手續費

題目鏈接
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。

題目描述
給定一個整數數組 prices,其中第 i 個元素代表了第 i 天的股票價格 ;非負整數 fee 代表了交易股票的手續費用。

你可以無限次地完成交易,但是你每筆交易都需要付手續費。如果你已經購買了一個股票,在賣出它之前你就不能再繼續購買股票了。

返回獲得利潤的最大值。

注意:這裏的一筆交易指買入持有並賣出股票的整個過程,每筆交易你只需要爲支付一次手續費。

示例 1:

輸入: prices = [1, 3, 2, 8, 4, 9], fee = 2
輸出: 8
解釋: 能夠達到的最大利潤:
在此處買入 prices[0] = 1
在此處賣出 prices[3] = 8
在此處買入 prices[4] = 4
在此處賣出 prices[5] = 9
總利潤: ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
注意:

0 < prices.length <= 50000.
0 < prices[i] < 50000.
0 <= fee < 50000.

題目分析

  1. 使用二維數組dp來定義當前股票的日期和狀態:dp[i][0]:第i天手裏沒有股票,dp[i][1]:第i天手裏有股票;
  2. dp[i][0]的上一個狀態是:dp[i-1][0]無操作和dp[i-1][1]賣出股票,即dp[i-1][1] + prices[i];
  3. dp[i][1]的上一個狀態是:dp[i-1][1]無操作和dp[i-1][0]買入股票,即dp[i-1][0] - prices[i] - fee;(fee爲買入股票手續費)
  4. 狀態轉移方程:dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i]);dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] - prices[i] - fee);
  5. 判斷邊界值:i-1==-1時, dp[i][0] = 0,dp[i][1] = -prices[i] - fee;
/**
 * @param {number[]} prices
 * @param {number} fee
 * @return {number}
 */
var maxProfit = function(prices, fee) {
    let len = prices.length;
    if(len == 0) return 0;
    let dp = new Array(len+1).fill(0).map(() => new Array(2).fill(0));
    for(let i=0; i<len; i++){
        if(i-1 == -1){
            dp[0][0] = 0;
            dp[0][1] = -prices[0]-fee;
            continue;
        }
        dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i]);
        dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i] - fee);
    }
    return dp[len-1][0];
};

130.股票的最大利潤

題目鏈接
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/gu-piao-de-zui-da-li-run-lcof
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。

題目描述
假設把某股票的價格按照時間先後順序存儲在數組中,請問買賣該股票一次可能獲得的最大利潤是多少?

示例 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。

限制:

0 <= 數組長度 <= 10^5

題目分析

  1. 定義min,max分別是數組中最小值和最大收益;
  2. 遍歷數組,按順序取出最小值,通過最小值計算收益,取出最大收益存放在max中;
  3. 返回max;
/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
    let n = prices.length;
    let min = prices[0];
    let max = 0;
    for(let i=1; i<n; i++){
        min = Math.min(min, prices[i]);
        max = Math.max(max, prices[i] - min);   
    }
    return max;
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章