leetcode股票买卖问题

leetcode上的股票买卖问题也属于比较经典的动态规划问题,其实上面的几道股票问题实际上思路是相同的,只不过处理时,状态繁简不一。从第一题的交易次数为1作为入门级引入此类问题,再到后来的步步深化,无不体现着动态规划的精妙之处。

在此类问题中,我们还是按照之前所说的思路,找【状态】,做【选择】,择优处理,返回最终结果。

在此题中,我们思考其状态可以得知此题的状态有:1.天数 2.该天是否持有股票
3.可交易的次数
做出的选择是:*“买入”*或者“卖出”票,且要注意的是:手上持有股票时才能卖出,且只有交易次数大于0时才能买入。

现在我们初步可以知道需要用一个三维数组来表示状态dp[][][],第三个维度用来表示股票的持有状态,用0表示未持有股票,1表示持有股票。
则dp[3][2][1]表示现在是第三天,总共能进行2次交易,且现在我持有股票。(记住如何解释「状态」,⼀旦你觉得哪⾥不好理解,把它翻译成⾃然语⾔就 容易理解了)
 现在我们初步可以知道需要用一个三维数组来表示状态dp[][][],第三个维度用来表示股票的持有状态,用0表示未持有股票,1表示持有股票。
则dp[3][2][1]表示现在是第三天,总共能进行2次交易,且现在我持有股票。
(记住如何解释「状态」,⼀旦你觉得哪⾥不好理解,把它翻译成⾃然语⾔就 容易理解了)我们想求的最终答案是	dp[n	-	1][K][0],即最后⼀天,最多允许	K	次交易, 最多获得多少利润。因为	[1]	代表⼿ 上还持有股票,[0]	表⽰⼿上的股票已经卖出去了,很显然后者得到的利润 ⼀定⼤于前者。   
 下面就是思考如何进行状态转移,dp[i][K][0](现在是第i天且未持有股票)和dp[i][K][1] (现在是第i天且持有股票)这两种状态如何由之前的状态转化而来。
 我们容易想到的是前一天和今天之间的状态是联系最紧密的,
 那么如何由前一天的状态转化到今天呢?经过一番思索我们得到如下状态转移方式(先用自然语言写出来然后再转化为代码形式)**dp[i][K][0]=(昨天就未持有股票且今天不进行交易则今天还是未持有股票OR昨天持有股票但今天卖出则今天变为未持有股票)。
 ****dp[i][K][1]=(昨天就持有股票今天不进行交易则今天还是持有股票OR昨天未持有股票但今天买入则今天变为持有股票)。
 **下面将其转化为代码```cppdp[i][K][0]=max(dp[i-1][K][0],dp[i-1][K][1]+prices[i]);dp[i][K][1]=max(dp[i-1][K][1],dp[i-1][K-1][0]-prices[i]);```
 此处我们定义买入时交易次数减一(同理可以定义卖出时交易次数减一,结果是一样的)

我们想求的最终答案是 dp[n - 1][K][0],即最后⼀天,最多允许 K 次交易, 最多获得多少利润。因为 [1] 代表⼿ 上还持有股票,[0] 表⽰⼿上的股票已经卖出去了,很显然后者得到的利润 ⼀定⼤于前者。

下面就是思考如何进行状态转移,dp[i][K][0](现在是第i天且未持有股票)和dp[i][K][1] (现在是第i天且持有股票)这两种状态如何由之前的状态转化而来。

我们容易想到的是前一天和今天之间的状态是联系最紧密的,那么如何由前一天的状态转化到今天呢?经过一番思索我们得到如下状态转移方式(先用自然语言写出来然后再转化为代码形式)

dp[i][K][0]=(昨天就未持有股票且今天不进行交易则今天还是未持有股票OR昨天持有股票但今天卖出则今天变为未持有股票)。

dp[i][K][1]=(昨天就持有股票今天不进行交易则今天还是持有股票OR昨天未持有股票但今天买入则今天变为持有股票)。

下面将其转化为代码

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

此处我们定义买入时交易次数减一(同理可以定义卖出时交易次数减一,结果是一样的)。

下面去哦们思考其base case:当交易次数K=0时,。下面去哦们思考其base case:当交易次数K=0时,最大利润肯定为0;即dp[-1][0][0]=dp[i][0][0]=0;
因为我们是从i=0开始(第一天开始),所当i=-1时利润为0,所以
dp[i][0][1]=dp[-1][K][1]=INT_MIN(不允许交易不可能持有股票,未开始时不会持有股票,均用负无穷来表示)。之所以要定义i=-1时的情况是因为i=0开始遍历时会出现i-1=-1的情况
下面以K=1来列出我们的代码(因为K=1是固定的,所以K不会影响最终的结果,所以可以把K去掉)

for(int i=0;i<n;i++){
if(i-1=-1){
//解释
//dp[i][0]=max(dp[-1][0],dp[-1][1]+prices[i])
//max(0,INT_MIN+prices[i])
dp[i][0]=0;
//解释
//dp[i][1]=max(dp[-1][1],dp[-1][0]-prices[i])
//=max(INT_MIN,0-prices[i])
dp[i][1]=-prices[i];
continue;
}
	dp[i][0]	=	Math.max(dp[i-1][0],	dp[i-1][1]	+	prices[i]);
	dp[i][1]	=	Math.max(dp[i-1][1],	-prices[i]);//这里之所以是-prices[i]是因为K=1,而前一天未持有股票而今天买入股票就对应交易次数变为0,故原本是dp[i-1][k-1][0]就=dp[i-1][0][0]恒为零 
	}
	return dp[n-1][0];

第⼀题就解决了,但是这样处理 base case 很麻烦,⽽且注意⼀下状态转移 ⽅程,新状态只和相邻的⼀个状态有关,其实不⽤整个 dp 数组,只需要⼀ 个变量储存相邻的那个状态就⾜够了,这样可以把空间复杂度降到 O(1):

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n=prices.size();
        int dp_i_0=0,dp_i_1=INT_MIN;
        for(int i=0;i<n;i++){
             dp_i_0=max(dp_i_0,dp_i_1+prices[i]);//注意此时两个dp_i_0是不同的含义,左边的是更新后的,而max括号里的是之前的状态,下同dp_i_1
             dp_i_1=max(-prices[i],dp_i_1);
        }
        return dp_i_0;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值