leetcode刷题笔记一百二十一题 买卖股票时机等相关问题

leetcode刷题笔记一百二十一题 买卖股票时机等相关问题

源地址:

121. 买卖股票的最佳时机

122. 买卖股票的最佳时机 II

123. 买卖股票的最佳时机 III

188. 买卖股票的最佳时机 IV

309. 最佳买卖股票时机含冷冻期

714. 买卖股票的最佳时机含手续费

问题描述:

本题解法参考了:https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/discuss/108870/Most-consistent-ways-of-dealing-with-the-series-of-stock-problems 英文题解中提到的关于状态转换的动态规划思想的方法

综合以上六题,股票交易整个过程主要受到三个因素影响:日期(股价),交易次数与是否持有股票。

三维数组为例, dp(i)(k)(0) 代表第i日股价,最多k次交易,不持有股票

初始状态方程:

//不持有股票且未进入交易日的初始状态显然为0
DP(-1)(k)(0) = 0
//持有股票但未进入交易日是不可能的,故使用Int.MinValue
DP(-1)(k)(1) = Int.MinValue

状态转换方程:

//DP(i)(k)(0)可能由两种状态转换而来,即选择rest保持i-1次不购买股票的结果,或是抛出i-1次时持有的股票
DP(i)(k)(0) = Math.max(DP(i-1)(K)(0), DP(i-1)(K)(1) + prices(i))
//DP(i)(k)(1)可能由两种状态转换而来,即选择继续持有i-1次保有的股票,或是可购买次数减一,购入当前股票
DP(i)(K)(1) = Math.max(DP(i-1)(K)(1), DP(i-1)(K-1)(0) - prices(i))
/**
** 基于上诉思路,121题要点在于只可以购买1次,因此K=1,但是所有的K都** 得到了限制,故进行忽略。
** 初始状态:dp_i10 = 0, dp_i11 = Int.MinValue
** 状态转换方程:
** DP(i)(1)(0) = Math.max(DP(i-1)(1)(0), DP(i-1)(1)(1)+price(i))
** DP(i)(1)(1) = Math.max(DP(i-1)(1)(1), DP(i-1)(0)(0)-price(i)) = Math.max(DP(i-1)(1)(1), -price(i))
*/
object Solution {
    def maxProfit(prices: Array[Int]): Int = {
        var dp_i10 = 0
        var dp_i11 = Int.MinValue

        for (price <- prices){
            dp_i10 = Math.max(dp_i10, dp_i11+price)
            dp_i11 = Math.max(dp_i11, -price)
        }

        return dp_i10
    }
}

---------------------------------------------------------

/**
**	122题的特点是解除了购买限制,K = +Infinity K可以忽略
**  初始状态:dp_i10 = 0,dp_i11 = Int.MinValue
**  状态转换方程:
** 	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)) = Math.max(DP(i-1)(K)(1), DP(i-1)(K)(0) - prices(i))
*/
object Solution {
    def maxProfit(prices: Array[Int]): Int = {
       var dp_i10 = 0
       var dp_i11 = Int.MinValue

       for (price <- prices){
           val dp_i10_old = dp_i10
           dp_i10 = Math.max(dp_i10, dp_i11+price)
           dp_i11 = Math.max(dp_i11, dp_i10_old-price)
       }
       return dp_i10
    }
}

---------------------------------------------------------

/**
** 123题的最大改变在于设置K的上限即 K=2
** 初始状态: dp_i10 = 0
       		dp_i11 = Int.MinValue
       		dp_i20 = 0
       		dp_i21 = Int.MinValue
** 状态转换方程:
	DP(i)(2)(0) = Math.max(DP(i-1)(2)(0), DP(i-1)(2)(1) + prices(i))
	DP(i)(2)(1) = Math.max(DP(i-1)(2)(1), DP(i-1)(1)(0) - prices(i))
	DP(i)(1)(0) = Math.max(DP(i-1)(1)(0), DP(i-1)(1)(1) + prices(i))
	DP(i)(1)(1) = Math.max(DP(i-1)(1)(1), DP(i-1)(0)(0) - prices(i)) = Math.max(DP(i-1)(1)(1), -prices(i))
*/
object Solution {
    def maxProfit(prices: Array[Int]): Int = {
       var dp_i10 = 0
       var dp_i11 = Int.MinValue
       var dp_i20 = 0
       var dp_i21 = Int.MinValue

       for (price <- prices){
           dp_i20 = Math.max(dp_i20, dp_i21+price)
           dp_i21 = Math.max(dp_i21, dp_i10-price)
           dp_i10 = Math.max(dp_i10, dp_i11+price)
           dp_i11 = Math.max(dp_i11, -price)
       }

       return dp_i20
    }
}

--------------------------------------------------------

/**
** 188题将123题泛化,K作为一个可输入的参数
** 这种情况需要注意K的取值,若K >= prices.length/2 认为使用K参** 数会造成爆栈,这情况下视K为正无穷情况处理
** 否则 初始状态:dp_ik0 = Array.fill(k+1)(0), dp_ik1 = Array.fill(k+1)(Int.MinValue)
** 状态转换方程:
** 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))
*/
object Solution {
    def maxProfit(k: Int, prices: Array[Int]): Int = {
        if (k >= prices.length/2) return maxProfit1(prices)

        val dp_ik0 = Array.fill(k+1)(0)
        val dp_ik1 = Array.fill(k+1)(Int.MinValue)

        for (price <- prices){
            for (j <- (1 to k).reverse){
                dp_ik0(j) = Math.max(dp_ik0(j), dp_ik1(j) + price)
                dp_ik1(j) = Math.max(dp_ik1(j), dp_ik0(j-1) - price)
            }
        }

        return dp_ik0(k)
    }

    def maxProfit1(prices: Array[Int]): Int = {
       var dp_i10 = 0
       var dp_i11 = Int.MinValue

       for (price <- prices){
           val dp_i10_old = dp_i10
           dp_i10 = Math.max(dp_i10, dp_i11+price)
           dp_i11 = Math.max(dp_i11, dp_i10_old-price)
       }

       return dp_i10
    }
}

--------------------------------------------------------

/**
**	309题在股票卖出后,增加了一日的冷冻期 故状态转换方程需要修改
**  需引入DP_IK0_PRE对应DP(i-2)(0)的值
**  初始状态:dp_ik0_pre = 0, dp_ik0 = 0, dp_ik1 = Int.MinValue
**  状态转换方程: 
**	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-2)(K-1)(0) - prices(i)) = Math.maxDP(i-1)(K)(1), DP(i-2)(K)(0) - prices(i))
*/
object Solution {
    def maxProfit(prices: Array[Int]): Int = {
        val length = prices.length
        if (length == 0 || length == 1) return 0
        var dp_ik0_pre = 0
        var dp_ik0 = 0
        var dp_ik1 = Int.MinValue

        for (price <- prices){
            val dp_ik0_old = dp_ik0
            dp_ik0 = Math.max(dp_ik0, dp_ik1 + price)
            dp_ik1 = Math.max(dp_ik1, dp_ik0_pre - price)
            dp_ik0_pre = dp_ik0_old
        }
        
        return dp_ik0
    }
}

--------------------------------------------------------

/**
**	708题 保持了K=+Infinity 但是每次交易增加了fee的费用
**  本题可以尝试在购入股票时收费,或卖出股票时收费
**  初始状态: dp_ik0 = 0, dp_ik1 = Int.MinValue
**  动态转换方程:
** 	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) - fee) = Math.max(DP(i-1)(K)(1), DP(i-1)(K)(0) - prices(i) - fee)
** 或者
** 	DP(i)(k)(0) = Math.max(DP(i-1)(K)(0), DP(i-1)(K)(1) + prices(i) - fee)
**  DP(i)(K)(1) = Math.max(DP(i-1)(K)(1), DP(i-1)(K-1)(0) - prices(i)) = Math.max(DP(i-1)(K)(1), DP(i-1)(K)(0) - prices(i))
*/
object Solution {
    def maxProfit(prices: Array[Int], fee: Int): Int = {
        var dp_ik0 = 0
        var dp_ik1 = Int.MinValue

        for (price <- prices){
            val dp_ik0_old = dp_ik0
            dp_ik0 = Math.max(dp_ik0, dp_ik1+price)
            dp_ik1 = Math.max(dp_ik1, dp_ik0_old - price -fee)
        } 
        return dp_ik0 
    }
}
posted @ 2020-08-13 01:11  ganshuoos  阅读(113)  评论(0编辑  收藏  举报