题目描述:
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。 注意:你不能在买入股票前卖出股票。
思路:
动态规划的 5 个步骤:
1、设定状态
这道题其实是一个典型的二维 dp 问题。「动态规划」用于多阶段最优化问题的求解。这里天数代表每个阶段,即一天一天看,设置为第一维。为了消除后效性(前面的状态确定下来以后不会因为后面状态而更改),将当天是否持股设置为第二维的状态。于是:
状态 dp[i][j] 表示:在下标为 i 的这一天,用户手上持股状态为 j 所获得的最大利润。
说明: j 只有 2 个值:0 表示不持股(特指卖出股票以后的不持股状态),1 表示持股。 「用户手上不持股」不代表用户一定在下标为 i 的这一天把股票抛售了;
2、思考状态转移方程
- dp[i][0] 怎样转移?
dp[i - 1][0] :当然可以从昨天不持股转移过来,表示从昨天到今天什么都不操作,这一点是显然的;
dp[i - 1][1] + prices[i]:昨天持股,就在下标为 i 的这一天,我卖出了股票,状态由 1 变成了 0,此时卖出股票,因此加上这一天的股价。
综上:dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
- dp[i][1] 怎样转移?
dp[i - 1][1] :昨天持股,今天什么都不操作,当然可以从昨天持股转移过来,这一点是显然的;
-prices[i]:注意:状态 1 不能由状态 0 来,因为事实上,状态 0 特指:「卖出股票以后不持有股票的状态」,请注意这个状态和「没有进行过任何一次交易的不持有股票的状态」的区别。
因此,-prices[i] 就表示,在下标为 i 的这一天,执行买入操作得到的收益。注意:因为题目只允许一次交易,因此不能加上 dp[i - 1][0]。
综上:dp[i][1] = max(dp[i - 1][1], -prices[i]);
3、考虑初始值
第 0 天不持股,显然 dp[0][0] = 0;
第 0 天持股,显然dp[0][1] = -prices[0]。
4、考虑输出
从状态转移方程可以看出,每一天的状态都考虑了之前的状态。在只发生一次交易的情况下,持有这支股票一定不能使我们获得最大利润。因此输出是 dp[len - 1][0],不可能是持股的状态 dp[len - 1][1],
作者:liweiwei1419 链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/bao-li-mei-ju-dong-tai-gui-hua-chai-fen-si-xiang-b/
代码:
class Solution {
public int maxProfit(int[] prices) {
//定义状态:dp[i][j]--在第i天,用户持股状态为j时所获得的最大利润。
//状态关系:dp[i][0]=max(dp[i-1][0],dp[i-1][1]+price[i]);
// dp[i][1]=max(dp[i-1][1],-price[i]); ---j不能由0->1,所以只是-price[i]
//初始值:dp[0][0]=0--不持股利润为0;dp[0][1]=-price[0]
//if(prices==null) return 0; wrong!
int len=prices.length;
if(len<2) return 0;
int[][] dp=new int[prices.length+1][2];
dp[0][0]=0;
dp[0][1]=-prices[0];
for(int i=1;i<prices.length;i++){
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]);
}
return dp[len-1][0];
}
}
来源:oschina
链接:https://my.oschina.net/u/4527334/blog/4358810