LeetCode 买卖股票的最佳时机 (动态规划)

目录

 

简介

分析

总结


简介

leetcode上面有几个关于买卖股票的动态规划题。下面我们来看这种问题的模型:

给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。

注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。这里说的K笔交易是一次买入和一次卖出!!!

分析

我们可以用三维DP去记录解决这个问题。

dp[i][k][0] = max( dp[i-1][k][0], dp[i-1][k][1] + a[i] )//卖出的时候,次数不变

dp[i][k][1] = max( dp[i-1][k][1], dp[i-1][k-1][0] - a[i] ) //买入的时候次数-1. 这里的是我们的约定,其实也可以反过来(卖出的时候-1次数)

第一维:表示第i天

第二维:表示当前最多进行k次交易

第三维:当前是否持有股票 1:持有,0:没有持有

递推式很容易理解,但是K值要分类讨论一下:

解法1: 当K为无穷大的时候,也就是可以无限交易的时候。无限交易的时候我们可以考虑贪心去解决,很显然,见好就收即可达到最优解。

解法2: 把上面的递推式令k=1,可得

    dp[i][0] = max(dp[i-1][0],dp[i-1][1] + a[i]);
    dp[i][1] = max(dp[i-1][1],dp[i-1][0] - a[i]);

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

class Solution {
public:
    int maxProfit(vector<int>& a) {
        
        int n = a.size();
        int ans = 0;
        for(int i = 1;i<n;++i){
            if(a[i] > a[i-1])ans += a[i] - a[i-1];//见好就收即可达到最优解
            
        }
        return ans;
    }
};



class Solution {
public:

    // dp[i][0] = max(dp[i-1][0],dp[i-1][1] + a[i]);
    // dp[i][1] = max(dp[i-1][1],dp[i-1][0] - a[i]);

    int maxProfit(vector<int>& a) {
        
        int n = a.size();
        if(!n)return 0;
        int dp_1,dp_0;
        for(int i = 0;i<n;++i){
            if(i == 0)
            {
                dp_1 = -a[i];
                dp_0 = 0;
                continue;
            }
            int tmp = dp_0;
            dp_0 = max(dp_0,dp_1 + a[i]);
            dp_1 = max(dp_1,tmp - a[i]);
            
        }
        return dp_0;
    }
};

所以原问题的解题思路:

当k >= n/2,都可以认为我们可以无限交易,可以采用上述贪心的方式;

当k < n/2 ,采用上述动态规划思路

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

class Solution {
public:
    int maxProfit(int k, vector<int> &prices) {
        if (prices.empty()) return 0;
        if (k >= prices.size()/2) return solveMaxProfit(prices);//贪心解决
        int n = prices.size();
        vector<vector<vector<int> > > dp(n,vector< vector<int> >(k+1,vector<int>(2,0)));
        
        for(int i = 0;i<n;++i)
            for(int j = 1;j<=k;++j)
            {
                if(i == 0) 
                {
                    dp[i][j][0] = 0;
                    dp[i][j][1] = -prices[i];
                    continue;
                }
                dp[i][j][0] = max(dp[i-1][j][0],dp[i-1][j][1] + prices[i]);
                dp[i][j][1] = max(dp[i-1][j][1],dp[i-1][j-1][0] - prices[i]);
            }
        return dp[n-1][k][0];
        
    }
    int solveMaxProfit(vector<int> &prices) {
        int res = 0;
        for (int i = 1; i < prices.size(); ++i) {
            if (prices[i] - prices[i - 1] > 0) {
                res += prices[i] - prices[i - 1];
            }
        }
        return res;
    }
};

总结

leetcode这道题的变种有好多道:

只能进行一次交易:最低点买入,最高点卖出即可

含手续费:在上面的递推式加上手续费即可

我认为先写上面两道题才能看清这道题的本质!

发布了257 篇原创文章 · 获赞 36 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/sgh666666/article/details/91874882