188买卖股票的最佳时机 IV(贪心+动态规划——困难)

1、题目描述

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

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

注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

2、示例

输入: [3,2,6,5,0,3], k = 2
输出: 7
解释: 在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。
     随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。

3、题解

基本思想:动态规划法,对于动态规划题,画出状态转移图。

我们具体到每一天,看看总共有几种可能的「状态」,每一天总共可能是六种状态,每种状态都是由前一天状态转移得到,再找出每个「状态」对应的「选择」。我们要穷举每一天所有「状态」下的最大收益,穷举的目的是根据对应的「选择」更新状态。(注意:已经交易次数是完整一次买入并卖出股票的次数,当买入股票还没有卖出股票不算一次交易算半次)

  • 0表示:dp[i++][0][0]第i天,已经交易次数0,手中没有股票状态下的最大收益,0状态可以无操作或者购买第i天股票进入1状态。
  • 1表示:dp[i++][0][1]第i天,已经交易次数0,手中持有股票状态下的最大收益,1状态可以无操作或者卖出第i天股票进入2状态,卖出股票交易数加1所以2状态为dp[i++][1][0]。
  • 2表示:dp[i++][1][0]第i天,已经交易次数1,手中没有股票状态下的最大收益,2状态可以无操作或者购买第i天股票进入3状态。
  • 3表示:dp[i++][1][1]第i天,已经交易次数1,手中持有股票状态下的最大收益,3状态可以无操作或者卖出第i天股票进入4状态,卖出股票交易数加1所以4状态为dp[i++][2][0]。
  • 4表示:dp[i++][2][0]第i天,已经交易次数2,手中没有股票状态下的最大收益,4状态可以无操作或者购买第i天股票进入5状态,但是状态5无意义,因为最多交易次数为2,就算购买了股票也不能卖,所以状态5不可能是最后返回的结果,状态5是dp[i++][2][1]。

综上分析:每一天总共可能是六种状态,每种状态都是由前一天状态转移得到,分别是已经交易次数0没有股票、已经交易次数0持有股票、已经交易次数1没有股票、已经交易次数1持有股票、已经交易次数2没有股票、已经交易次数2持有股票。只要求出每一天六种状态下每种状态最大收益就是局部最优,最后返回六种状态下最大值就是全局最优。但是其实某些状态是不存在的,比如第一天已经交易次数1持有股票才第一天不可能已经交易一次,这些状态初始设定为负无穷。

最后返回最后一天下0-4这五种状态下收益中的最大值,因为状态1和3都是买入了股票还没卖出去,所以肯定不是最后的返回结果和状态5情况一样,所以最后返回0、1、3三种状态下收益中的最大值。(0状态是可能存在的,如果股票一直下跌,交易员就不会进行交易,最后返回收益最大值就是0状态)

  • dp[i][k][0 or 1]表示第i天,已经交易次数k,手上是否持有股票状态下的最大收益(已经交易次数是完整一次买入并卖出股票的次数,当买入股票还没有卖出股票不算一次交易算半次)
  • 起始状态应该是dp[0][0][0]=0:第1天,已经交易次数0,手中没有股票,收益为0。或者dp[0][0][1] = -prices[0]第1天,已经交易次数0,手上持有股票,则买入了第1天的股票收益为-prices[0]
  • 遍历第1天之后的每天股票情况
  • 计算每一天六种状态下的最大收益,k=0、1、2
  • 第i天,已经交易次数k,手中没有股票状态下的最大收益等于max(1、无操作:前一天此状态下的收益;2、卖出股票:前一天的持有股票下的最大收益+今天股票价格,因为卖出股票交易数k+1)。对应代码dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k - 1][1] + prices[i])
  • 第i天,已经交易次数k,手中持有股票状态下的最大收益等于max(1、无操作:前一天此状态下的收益;2、买入股票:前一天的没有股票下的最大收益-今天股票价格,因为买入股票还没有卖出交易数不变)。对应代码dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k][0] - prices[i])
  • 返回最后一天没有股票状态下交易0次、1次、2次中最大的收益值
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Solution {
public:
	int maxProfit(int k, vector<int>& prices) {
		//基本思想:贪心+动态规划
		if (prices.size() == 0)
			return 0;
		int res = 0;
		//当允许交易的次数大于交易天数时,相当于是可以无限交易,使用贪心算法
		//否则当k过大,dp分配不了那么多内存空间
		if (k > prices.size()/2)
		{
			for (int i = 1; i < prices.size(); i++)
			{
				if (prices[i] > prices[i - 1])
					res += prices[i] - prices[i - 1];
			}
			return res;
		}
		//dp[i][k][0 or 1]表示第i天,已经交易次数k,手上是否持有股票状态下的最大收益
		vector<vector<vector<int>>> dp(prices.size(), vector<vector<int>>(k + 1, vector<int>(2, 0)));
		//初始状态设置
		dp[0][0][0] = 0;
		dp[0][0][1] = -prices[0];
		for (int i = 1; i < k + 1; i++)
		{
			dp[0][i][0] = -999999;
			dp[0][i][1] = -999999;
		}
		//遍历第1天之后的每天股票情况,计算每一天的2*(k+1)种状态下的最大收益
		for (int i = 1; i < prices.size(); i++)
		{
			for (int j = 0; j < k + 1; j++)
			{
				//第i天,已经交易次数j,手中没有股票下的最大收益等于max(1、无操作:前一天此状态下的收益;2、卖出股票:前一天的持有股票下的最大收益+今天股票价格,因为卖出股票交易数j+1)
				if (j != 0)
					dp[i][j][0] = max(dp[i - 1][j - 1][1] + prices[i], dp[i - 1][j][0]);
				//第i天,已经交易次数j,手中持有股票状态下的最大收益等于max(1、无操作:前一天此状态下的收益;2、买入股票:前一天的没有股票下的最大收益 - 今天股票价格,因为买入股票还没有卖出交易数不变)
				dp[i][j][1] = max(dp[i - 1][j][0] - prices[i], dp[i - 1][j][1]);
			}
		}
		//最后最大收益一定是手中不持有股票,所以返回最后一天不持有股票的k+1种状态下的最大收益
		for (int i = 0; i < k + 1; i++)
			res = max(res, dp[prices.size() - 1][i][0]);
		return res;
	}
};
int main()
{
	Solution solute;
	vector<int> prices = { 3,2,6,5,0,3 };
	int k = 2;
	cout << solute.maxProfit(k, prices) << endl;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值