码迷,mamicode.com
首页 > 其他好文 > 详细

Best Time to Buy and Sell Stock with Cooldown

时间:2016-06-24 10:45:45      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:

题目:

给定一个数组nums,nums[i]代表的是在第i天的股价
  例如:[1,2,3,0,10,4],数组代表的含义是:有6天的股价给你了,从第一天到第六天的股价分别是 1,2,3,0,10,4
  你买卖股票的次数不限,但是有两个限制:

    1. 卖不能在买前面(不能买10,卖0)
    2. 一次交易完成之后,至少休息一天才能继续买入(买1,卖3之后,不能立刻买0,必须至少等一天)

问题:求出最大的获利数(对于例子来说,max=11,买1卖2,休息一天,买0卖10)


 

思路:
用dp来解。dp就一定要有状态和状态转换方程。

在每一天,都有3种状态:

  1.   buy
  2.   sell
  3.   rest

那么我们就可以根据给定的数组,新建三个状态数组,代表每天对应的状态。
buy[n], sell[n], rest[n](n代表给定数组的长度)
那么状态就有了表示方法:
buy[i]:在第i天之前,以buy为结束的任何交易组合的最大利润
sell[i]:在第i天之前,以sell为结束的任何交易组合的最大利润
rest[i]:在第i天之前,以rest为结束的任何交易组合的最大利润
状态转换方程:(price是当前日期的股价)

  buy[i] = max(rest[i-1] - price, buy[i-1]) 
  sell[i] = max(buy[i-1] + price, sell[i-1])
  rest[i] = max(sell[i-1], buy[i-1], rest[i-1])

以上的状态转换方程只是把题目的要求和之前的分析总结起来,例如:buy[i] = 今天买入(必须在休息之后才能买入) 或者 之前就有买入,保持不卖出
还有一个隐藏的要素:
  rest[i] = sell[i-1] 这个等式的意义在于,如果在今天休息,那么这天的收益就跟前一天sell相同
那么把这个等式代入,就有:

    buy[i] = max(sell[i-2] - price, buy[i-1])
    sell[i] = max(buy[i-1] + price, sell[i-1])

很好理解,如果要在这一天卖的话,至少要在前两天把之前的股票卖掉(因为间隔为1天)

在这之后,还可以更进一步优化,这里我们可以发现第i天的状态和第i-1天和第i-2天的状态有关,那么就可以不用状态数组,用两个变量来保存i-1和i-2的数据


 

代码:

 1     public int maxProfit(int[] prices) {
 2         int sell = 0, prevSell = 0, buy = Integer.MIN_VALUE, prevBuy;
 3         for (int price : prices) {
 4             prevBuy = buy;
 5             buy = Math.max(prevSell - price, prevBuy); //这里buy和sell的赋值顺序不能变,因为prevSell在这里相当于方程中的sell[i-2]
 6             prevSell = sell; //到这里,prevSell就真正变成了sell[i-1],变成了真正的previous sell
 7             sell = Math.max(prevBuy + price, prevSell);
 8         }
10         return sell;
11     }

 

Best Time to Buy and Sell Stock with Cooldown

标签:

原文地址:http://www.cnblogs.com/marshallguo/p/5613242.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!