这次这道题我想了好久。
对于通常的DP问题,我一般都会这么思考
1.找出每一个状态的最优解
2.再找相邻状态的关系
怎么也找不出来f(n) f(n-1)…之间的关系,后面看了答案,看到实际解题思路2恍然大悟
实际解题思路1:
使我们感兴趣的点是数字折线图中的峰和谷。我们需要找到最小的谷之后的最大的峰。
我们可以维持两个变量——minprice 和 maxprofit,它们分别对应迄今为止所得到的最小的谷值和最大的利润(卖出价格与最低价格之间的最大差值)
代码如下
public int maxProfit(int[] prices) {
if(prices.length==0){
return 0;
}
int max =0;
int min = prices[0];
for(int i=1;i<prices.length;i++){
min = Math.min(min,prices[i]);
max = Math.max(max,prices[i]-min);
}
return max;
}
实际解题思路2(DP):
怎么与前一天的状态关联起来呢?
把股票每一天和前一天的价格差写成一个差价数组。
求买卖一次股票所能产生的最大收益相当于求这个差价数组的最大子数组, 因为在第 N 天买入第 M 天卖出得到的总收益就等于从 N 到 M 之间每天股票价格变化的总和.
关于最大子数组的问题可以参考这道题: 53. 最大子序和
关于Kadane算法
最大子数组问题最早于1977年提出, 直到1984年卡内基梅隆大学的 Jay Kadane 才提出了该问题的线性算法.
更多细节详见维基百科最大子数列问题
可以用动态规划的思路来理解Kadane算法:
如果 max_here > 0,则说明 max_here 对截止当前元素的结果有增益效果,则 max_here 保留并加上当前遍历数字
如果 max_here <= 0,则说明 max_here 对截止当前元素的结果无增益效果,需要舍弃,则将 max_here 直接更新为当前遍历数字
将 计算每日差价 和 Kadane算法 写在一个迭代里后, 具体代码如下:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if len(prices) == 0:
return 0
prev = prices[0]
max_profit = 0
max_here = 0
for t in prices[1:]:
x = t - prev
prev = t
max_here = max_here + x if max_here > 0 else x
max_profit = max(max_profit, max_here)
return max_profit
没写完,待编辑