121. 买卖股票的最佳时机
思路
贪心
因为股票就买卖一次,那么贪心自然就是取最左最小值,取最右最大值,那么得到的差值就是最大利润。
动态规划
- 确定dp数组(dp table)以及下标的含义
dp[i][0] 表示第i天持有股票所得现金(一开始现金是0,那么加入第i天买入股票现金就是 -prices[i], 这是一个负数)。
dp[i][1] 表示第i天不持有股票所得现金
注意这里说的是“持有”,“持有”不代表就是当天“买入”!也有可能是昨天就买入了,今天保持持有的状态 - 确定递推公式
如果第i天持有股票即dp[i][0], 那么可以由两个状态推出来:第i-1天就持有股票,那么就保持现状;第i天买入股票。那么dp[i][0]应该选所得现金最大的,所以dp[i][0] = max(dp[i - 1][0], -prices[i]);
如果第i天不持有股票即dp[i][1], 也可以由两个状态推出来:第i-1天就不持有股票,那么就保持现状;第i天卖出股票。同样dp[i][1]取最大的,dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]); - dp数组如何初始化
dp[0][0]表示第0天持有股票,此时的持有股票就一定是买入股票了,所以dp[0][0] -= prices[0];
dp[0][1]表示第0天不持有股票,不持有股票那么现金就是0,所以dp[0][1] = 0; - 确定遍历顺序
从递推公式可以看出dp[i]都是有dp[i - 1]推导出来的,那么一定是从前向后遍历。
代码
贪心:
class Solution {
public int maxProfit(int[] prices) {
int ans = 0;
int low = Integer.MAX_VALUE;
for(int i=0;i<prices.length;i++){
low = Math.min(low,prices[i]);
ans = Math.max(ans,prices[i]-low);
}
return ans;
}
}
动态规划:
class Solution {
public int maxProfit(int[] prices) {
int[][] dp = new int[prices.length][2];
//第0天持有股票
dp[0][0] = -prices[0];
//第0天不持有股票
dp[0][1] = 0;
for(int i=1;i<prices.length;i++){
dp[i][0] = Math.max(dp[i-1][0],-prices[i]);
dp[i][1] = Math.max(dp[i-1][1],prices[i]+dp[i-1][0]);
}
return dp[prices.length-1][1];
}
}