力扣-309-最佳买卖股票时机含冷冻期

查了下,类型题大概有6道

题目描述:

  1. 可以多次买卖,但是每次只能执行一笔买卖
  2. 卖出后的第二天无法操作(买入)

求最大获利

买卖股票的原题是一次买入卖出,所以关键是找到最便宜的买入价格,这里很明显不太一样
不仅要考虑多笔,还要考虑每一次操作后的冷冻期对总利润带来的影响

我们先不考虑冷冻期,那么多笔买入卖出的最大利润怎么做?
这不就是122-买卖股票的最佳时机Ⅱ

说实话,看完回来觉得如果用那个巧妙简洁的脑筋急转弯写法,对这题没什么参考意义

我似乎也明白为什么刷题笔记和热题100为什么没有Ⅱ而是这道题了,同一天卖出买入确实是个BUG
所以才有了冷冻期和手续费吧

感觉冷冻期像不像打家劫舍的报警机制?对吧,打劫了这一户就不能打劫下一户/今天卖出了,明天就不能买入

三种状态,hold持有可卖出,nothold不持有且可以买入,freeze不持有而且不能买入:

  1. 持有:
    可以是之前就买入持有的,今天仍然持有没有卖出,最大收益就是回推一步hold[i-1];也可以是今天刚买入的,而且昨天不能是卖出(手上没有就一定卖不了…但具体是哪一个呢?就算是昨天冷冻期今天也可以买入,但是如果不是冷冻期就有可能卖出,所以这里只要freeze),会导致今天冷冻期,收益是freeze[i-1]-prices[i]

状态转移方程:hold[i] = max(hold[i-1],freeze[i-1]-prices[i])

  1. 不持有,而且可以买入:可以是今天刚刚卖出,那么昨天必须持有hold[i-1]+prices[i];也可以是昨天就没持有了(反正没买,能不能买无所谓),今天也没买max(notHold[i-1],freeze[i-1])
  2. 不持有,而且不能买入:一定是昨天把股票卖掉了,今天才会被冷冻,今天就不能买也不能卖notHold[i-1]

考虑初始化,第一天持有的收益是-prices[0]

我不确定,但是这确实能过

int maxProfit(vector<int>& prices) {
	int n = prices.size();
	vector<int> hold(n),notHold(n,0),freeze(n,0);

	hold[0] = -prices[0];

	for (int i = 1; i < n; i++) {
		hold[i] = max(hold[i - 1],  freeze[i - 1] - prices[i]);
		notHold[i] = max(hold[i-1]+prices[i],max(notHold[i - 1], freeze[i - 1]));
		freeze[i] = notHold[i - 1];
	}

	return max(notHold[n - 1], freeze[n - 1]);
}

相当于三个动态规划一维数组

		notHold[i] = max(hold[i-1]+prices[i],max(notHold[i - 1], freeze[i - 1]));
		freeze[i] = notHold[i - 1];

然后我们看到freeze数组就是简单的由notHold[i-1]转移过来的

所以可以把它优化掉,即从三种状态优化为2种状态

// 好吧这里不是这么简单,因为直接去掉变成notHold[i-2]会出现越界问题
// 但是少我们可以把freeze从一个数组先优化为一个变量
// 同理,hold和notHold也可以,但需要两个变量
// 需要额外考虑没有进入循环的情况,notHold需要显式初始化为0
int maxProfit(vector<int>& prices) {
	int n = prices.size();
	int freeze = 0, preHold = -prices[0], preNotHold = 0,hold,notHold;

	for (int i = 1; i < n; i++) {
		hold = max(preHold,  freeze - prices[i]);
		notHold = max(preHold+prices[i],max(preNotHold, freeze));
		freeze = preNotHold;
		preHold = hold;
		preNotHold = notHold;
	}

	return max(notHold, freeze);
}

下次再想怎么简化为两状态

posted @ 2022-11-11 09:30  YaosGHC  阅读(36)  评论(0)    收藏  举报