zoukankan      html  css  js  c++  java
  • 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 
        }
    }
    
  • 相关阅读:
    按钮常用
    MySQL常用Json函数
    MySQL所有函数及操作符
    MySQL常用时间函数
    MySQL常用聚合函数
    Shiro整合Spring
    Shiro集成Web
    Shrio授权验证详解
    Shrio认证详解+自定义Realm
    Shiro入门
  • 原文地址:https://www.cnblogs.com/ganshuoos/p/13494031.html
Copyright © 2011-2022 走看看