zoukankan      html  css  js  c++  java
  • 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];
        }
    };
    
  • 相关阅读:
    PAT 1010. 一元多项式求导 (25)
    PAT 1009. 说反话 (20) JAVA
    PAT 1009. 说反话 (20)
    PAT 1007. 素数对猜想 (20)
    POJ 2752 Seek the Name, Seek the Fame KMP
    POJ 2406 Power Strings KMP
    ZOJ3811 Untrusted Patrol
    Codeforces Round #265 (Div. 2) 题解
    Topcoder SRM632 DIV2 解题报告
    Topcoder SRM631 DIV2 解题报告
  • 原文地址:https://www.cnblogs.com/Vicky1361/p/14723232.html
Copyright © 2011-2022 走看看