题目描述:
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 若是你最多只容许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。 注意:你不能在买入股票前卖出股票。java
思路:
动态规划的 5 个步骤:算法
一、设定状态
这道题实际上是一个典型的二维 dp 问题。「动态规划」用于多阶段最优化问题的求解。这里天数表明每一个阶段,即一天一天看,设置为第一维。为了消除后效性(前面的状态肯定下来之后不会由于后面状态而更改),将当天是否持股设置为第二维的状态。因而:数组
状态 dp[i][j] 表示:在下标为 i 的这一天,用户手上持股状态为 j 所得到的最大利润。优化
说明: j 只有 2 个值:0 表示不持股(特指卖出股票之后的不持股状态),1 表示持股。 「用户手上不持股」不表明用户必定在下标为 i 的这一天把股票抛售了;ui
二、思考状态转移方程
- dp[i][0] 怎样转移?
dp[i - 1][0] :固然能够从昨天不持股转移过来,表示从昨天到今天什么都不操做,这一点是显然的;设计
dp[i - 1][1] + prices[i]:昨天持股,就在下标为 i 的这一天,我卖出了股票,状态由 1 变成了 0,此时卖出股票,所以加上这一天的股价。code
综上:dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);leetcode
- dp[i][1] 怎样转移?
dp[i - 1][1] :昨天持股,今天什么都不操做,固然能够从昨天持股转移过来,这一点是显然的;it
-prices[i]:注意:状态 1 不能由状态 0 来,由于事实上,状态 0 特指:「卖出股票之后不持有股票的状态」,请注意这个状态和「没有进行过任何一次交易的不持有股票的状态」的区别。io
所以,-prices[i] 就表示,在下标为 i 的这一天,执行买入操做获得的收益。注意:由于题目只容许一次交易,所以不能加上 dp[i - 1][0]。
综上:dp[i][1] = max(dp[i - 1][1], -prices[i]);
三、考虑初始值
第 0 天不持股,显然 dp[0][0] = 0;
第 0 天持股,显然dp[0][1] = -prices[0]。
四、考虑输出
从状态转移方程能够看出,每一天的状态都考虑了以前的状态。在只发生一次交易的状况下,持有这支股票必定不能使咱们得到最大利润。所以输出是 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]; } }