• leetcode股票系列题目——动态规划


    总结:

    • 前四道都可以用二维DP,定义状态第一维代表当前天数,第二维代表当天持有股票和不持有股票两种状态,dp[ i ] [ 0 ] 代表第 i + 1 天(下标是从0开始) 不持有股票的状态,dp[ i ] [ 1 ] 表示第 i + 1 天持有股票的状态时收益最大。
    • 状态转移,当天不持有股票可以从前一天就不持有的状态转移过来,也可以是前一天持有但是现在卖出的状态转移过来,当天持有股票的状态可以从前一天就持有状态转移,也可以是前一天不持有股票但是现在买入的状态转移过来。
    • 求最大收益,就取以上状态中的最大值即可,最大收益在最后一天的卖出状态取得

    121. 买卖股票的最佳时机(一次交易)

    class Solution {
    public:
     int maxProfit(vector<int>& prices) {
        	int n = prices.size();
        	vector<vector<int>> dp(n, vector<int>(2,0));
            //初始化baseCase,第1天不持有股票的最大收益为0,第1天持有股票的最大收益(在第一天买入)
        	dp[0][0] = 0, dp[0][1] = -prices[0];  
        	for(int i = 1;i < n;i++){
        		dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i]);
        		dp[i][1] = max(dp[i-1][1], -prices[i]);  //只允许一次交易,之前的交易收益视为0
    	}
        	return dp[n-1][0];
        }
    };
    

    122. 买卖股票的最佳时机2 (多次交易)

    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
        	int len = prices.size();
        	vector<vector<int>> dp(len,vector<int>(2,0));
    	dp[0][0] = 0, dp[0][1] = -prices[0];
    	for(int i = 1;i < len;i++){
    		dp[i][0] = max(dp[i-1][0],dp[i-1][1] + prices[i]);
    		dp[i][1] = max(dp[i-1][1],dp[i-1][0] - prices[i]);  //考虑上一次交易收益
    	} 
            
            return dp[len-1][0];
        }
    };
    

    309. 最佳买卖股票时机含冷冻期(在上一次交易后需要等待一天才能购入)

    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
        	int n = prices.size();
    
            if(n < 2){  //因为初始化前两天的状态,所以需要考虑prices长度小于2
                return 0;
            }
        	int dp[n][2];    //0 - 不持有股票,1 - 持有股票 
        	//初始化前两天的baseCase
        	dp[0][0] = 0;
    	dp[0][1] = -prices[0];
    	dp[1][0] = max(dp[0][0], dp[0][1] + prices[1]);
    	dp[1][1] = max(dp[0][1], -prices[1]); //第二天购入只能是第一天购入或者第二天购入
    		
    	for(int i = 2;i < n;i++){
    		dp[i][0] = max(dp[i-1][0],dp[i-1][1] + prices[i]);
                    //当前状态为买入,只能是前一天没买入,前两天卖出再买入 
    		dp[i][1] = max(dp[i-1][1],dp[i-2][0] - prices[i]);  
    	} 
    	return dp[n-1][0];
        }
    };
    

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

    class Solution {
    public:
        int maxProfit(vector<int>& prices, int fee) {
        	int n = prices.size();
        	int dp[n][2];  
        	dp[0][0] = 0;
        	dp[0][1] = -prices[0];
        	for(int i = 1;i < n;i++){
        		dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i] - fee);//一次交易减去手续费 
        		dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i]);
    	} 
        	
        	return dp[n-1][0];
        }
    };
    

    后面两题限制交易次数,所以需要再加一维表示次数,但是对于baseCase初始化边界暂时还不是很理解,这里只记录了自己认为比较好理解的方法

    123. 买卖股票的最佳时机3(限制交易两次)

    思路:考虑交易两次所有的状态,使用变量记录

    • 交易两次一共有5种状态,不操作(free)、第一次买入(buy1)、第一次卖出(sell1)、第二次买入(buy2)、第二次卖出(sell2),但是由于不操作对于收益为0,所以可以简单考虑后面四种状态

    • 将 i - 1天的这四种状态,如何转移到第i天,

      buy1_i : 第 i - 1 天第一次买入(buy1_i-1)之后没有操作, 或者第 i 天 才第一次买入

      sell1_ i : 第 i - 1 天第一次卖出(sell1_i-1)之后没有操作, 或者第 i - 1 天第一次买入第 i 天第一次卖出

      buy2_i : 第 i - 1天第二次买入(buy2_i-1)之后没有操作, 或者第 i - 1天第一次卖出后第 i 天第二次买入

      sell2_i : 第 i - 1 天第二次卖出(sell2_i-1)之后没有操作, 或者第 i - 1天第二次买入后第 i 天第二次卖出

    • 最大收益由于始终维护的是最大值,并且同一天买入和卖出不影响收益这一宽松条件使得,sell2处获得的是最终的最大收益

    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            int n = prices.size();
            int buy1 = -prices[0];
            int sell1 = 0;
            int buy2 = -prices[0];
            int sell2 = 0;
            for(int i = 0;i < n;i++){
                buy1 = max(buy1, -prices[i]);
                sell1 = max(sell1, buy1 + prices[i]);
                buy2 = max(buy2, sell1 - prices[i]);
                sell2 = max(sell2, buy2 + prices[i]);
            }
            return sell2;
        }
    };
    

    188. 买卖股票的最佳时机4(限制K次交易)

    思路:考虑k次交易可能存在的所有状态

    • 进行k次交易总共存在2*k + 1次状态(无操作,第k次买入,第k次卖出 = 1 + k + k)

    • 将状态分为两大类(买入和卖出),[1 - 2*k]中 奇数次代表买入,偶数次代表卖出,初始化baseCase,第一天的状态中买入操作初始化为 -prices[0],卖出操作和不操作收益都为0

    • 第 i 天的状态由第 i - 1天的状态转移而来,

      第 i 天买入可以是第 i - 1 天的买入(不操作) 或者 第 i - 1 天的卖出后买入

      第 i 天卖出可以是第 i - 1 天卖出(不操作) 或者 第 i - 1天买入后卖出

    • dp中偶数次维护的是截至到第 i 天 第 k 次交易(卖出)最大收益,最终最大收益 = dp[2 * k]

    class Solution {
    public:
        int maxProfit(int k, vector<int>& prices) {
            int n = prices.size();
            
    	k = min(k, n/2);  //prices天数不够K次交易的情况,取k 和 n/2 中的最小值 
            
            vector<int> dp(2*k+1,0);  //0代表不操作,奇数代表买,偶数代表卖
           
    	    //初始化第1天状态的baseCase
            for(int i = 1;i < 2*k+1;i++){
                if(i % 2){
                    dp[i] = -prices[0];  //第1天的所有奇数次状态买入,偶数次卖出收益0 
                }
            }
            for(int i = 1;i < n;i++){
                for(int j = 1;j < 2*k+1;j++){
                    if(j % 2 != 0){
                        dp[j] = max(dp[j], dp[j-1] - prices[i]);  //买入 
                    }else{
                        dp[j] = max(dp[j], dp[j-1] + prices[i]);  //卖出 
                    }
                }
            }
            return dp[2*k];
        }
    };
    
  • 相关阅读:
    ASP.NET中的DataBinder.Eval用法
    jquery Ajax调用asmx和ashx代码示例三级联动
    项目中使用的架构
    asp.net(c#)上传图片到数据库
    asp.net(c#)从数据库里读取图片并显示到页面
    一款好的UI草图设计软件
    Windows Azure云平台(无须提供信用卡)[转]
    推荐8个超棒的学习 jQuery 的网站
    推荐两个界面原型设计工具GUIDesignStudio 和 Mockups For Desktop
    在VS2010上使用C#调用非托管C++生成的DLL文件(图文讲解)
  • 原文地址:https://www.cnblogs.com/Vicky1361/p/14723232.html
Copyright © 2020-2023  润新知