zoukankan      html  css  js  c++  java
  • 刷题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;
    };
    

      

  • 相关阅读:
    poj 2763 Housewife Wind
    hdu 3966 Aragorn's Story
    poj 1655 Balancing Act 求树的重心
    有上下界的网络流问题
    URAL 1277 Cops and Thieves 最小割 无向图点带权点连通度
    ZOJ 2532 Internship 网络流求关键边
    ZOJ 2760 How Many Shortest Path 最大流+floyd求最短路
    SGU 438 The Glorious Karlutka River =) 拆点+动态流+最大流
    怎么样仿写已知网址的网页?
    5-10 公路村村通 (30分)
  • 原文地址:https://www.cnblogs.com/liu-xin1995/p/12774519.html
Copyright © 2011-2022 走看看