Best Time to Buy and Sell Stock

Say you have an array for which the ith element is the price of a given stock on day i. Design an algorithm to find the maximum profit. You may complete at most two transactions.

Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).

Example 1:

Input: [3,3,5,0,0,3,1,4]
Output: 6
Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
  Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.

Example 2:

Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
  Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
  engaging multiple transactions at the same time. You must sell before buying again.

Example 3:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

思路

这个题目有一系列的变形,唯一改变的是交易的次数,比如这题中限定的最多transaction是2,当然也可以限定为k。

解法还是dp,dp[k, i] 代表在price[i]之前 (price[0] ~ price[i])完成最多k个transaction所获得的最大利润,注意这里不是说以price[i]为结束,只是限定了k个transaction的大致范围,很有可能在k个transaction中是不包含price[i]的。那么得出:

dp[k, i] = max(dp[k, i-1], price[i] - price[ii] + dp[k-1, ii])       其中 ii在[0, i-1]范围内

   = max(dp[k, i-1], price[i] + max(dp[k-1, ii] - price[ii]))      其中 ii 在[0, i-1]范围内

dp[0, i] = 0

dp[k, 0] = 0

解决 k transaction 的代码如下,计算过程我看的有点蒙。

注意的是自低向上的计算过程,先计算 dp[1][1]~dp[1][n],也就是先从k=1,最多只有一笔交易的情况出发,然后去计算dp[2][1]~dp[2][n]......直到dp[k][1]~dp[k][n]。在计算dp[1][1]~dp[1][n]时,假设当前计算的是dp[1][i],会利用到dp[1][i-1],即第一笔交易是在0~i-1内的price完成,和price[i]没有关系。还要计算另一种情况,就是i计算在内,因为i是末位,所以只可能在price[i]卖出,但是和这个相对应的买入位不确定,所以要遍历i之前所有可能的买入位,即计算所有的 price[i]-price[ii],其中ii在0~i-1之间,那么之前的k-1笔交易只可能是在0~ii之内的,至于这里为什么包括ii,而不是ii-1,我猜是因为可以在同一天先卖后买,比如说我在第ii-1天先将手中持有的stcock卖出,再买入。

明白了上面之后,在计算dp[1][1]~dp[1][n],时如果确定了i,那么要计算所有的 price[i]-price[ii],取其price[i]-price[ii]+dp[0][ii-1]最大的一个,,ii在0~i-1之间,当i递增变为i+1时,又得计算所有的 price[i+1]-price[ii],其中ii在0~i之间,这样会重复计算的,所以要利用之前的计算结果,可以重复利用的是dp[0][i-1]-price[ii]这里,因为ii在0~i-1遍历,所以比如0~1,0~2以及0~3,计算0~3只需要计算dp[0][2]-price[2]的值,和之前0~2的计算结果直接相比即可。

感觉描述得有点乱,就是说在dp[i][j],i固定的情况下,dp[i-1][jj]-price[jj]的值由jj决定,当j增大时,比如从4到5,那么jj就是在 0~3和0~4中,这两个计算中0~3的计算是重复的,当j=4时我们只需要计算dp[1][3]-price[3]后再直接和上一次的结果比,再取较大的即可。这样我们在计算dp[1][1]到dp[1][n]时只需要计算开始处的dp[0][0]-price[0]再往后后项依赖前项递推即可。

/**
* dp[i, j] represents the max profit up until prices[j] using at most i transactions.
* dp[i, j] = max(dp[i, j-1], prices[j] - prices[jj] + dp[i-1, jj]) { jj in range of [0, j-1] }
* = max(dp[i, j-1], prices[j] + max(dp[i-1, jj] - prices[jj]))
* dp[0, j] = 0; 0 transactions makes 0 profit
* dp[i, 0] = 0; if there is only one price data point you can't make any transaction.
*/
public int maxProfit(int k, int[] prices) {
int n = prices.length;
if (n <= 1)
return 0; //if k >= n/2, then you can make maximum number of transactions.
if (k*2 >= n) {
int maxPro = 0;
for (int i = 1; i < n; i++) {
if (prices[i] > prices[i-1])
maxPro += prices[i] - prices[i-1];
}
return maxPro;
} int[][] dp = new int[k+1][n];
  
for (int i = 1; i <= k; i++) {
int localMax = dp[i-1][0] - prices[0];
for (int j = 1; j < n; j++) {
dp[i][j] = Math.max(dp[i][j-1], prices[j] + localMax);
localMax = Math.max(localMax, dp[i-1][j] - prices[j]);
}
}
return dp[k][n-1];
}

算法要点:

1. dp[i, j] represents the max profit up until prices[j] using at most i transactions。这个含义要注意,即到了第j天时最多用掉了i笔交易所获得的最大利润

2. 基于以上的定义,计算

dp[i, j] = max(dp[i, j-1], prices[j] - prices[jj] + dp[i-1, jj]) { jj in range of [0, j-1] }

时 jj 的范围每次都是从0 到j-1

3. localMax那块的计算逻辑

LeetCode解题报告—— Best Time to Buy and Sell Stock的更多相关文章

  1. 解题报告Best Time to Buy and Sell Stock with Cooldown

    题目 Say you have an array for which the ith element is the price of a given stock on day i. Design an ...

  2. 【一天一道LeetCode】#122. Best Time to Buy and Sell Stock II

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Say you ...

  3. 【LeetCode】188. Best Time to Buy and Sell Stock IV 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  4. 【LeetCode】309. Best Time to Buy and Sell Stock with Cooldown 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 动态规划 日期 题目地址:https://leetc ...

  5. 【LeetCode OJ】Best Time to Buy and Sell Stock III

    Problem Link: http://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/ Linear Time Solut ...

  6. 【leetcode】123. Best Time to Buy and Sell Stock III

    @requires_authorization @author johnsondu @create_time 2015.7.22 19:04 @url [Best Time to Buy and Se ...

  7. LeetCode 笔记23 Best Time to Buy and Sell Stock III

    Best Time to Buy and Sell Stock III Say you have an array for which the ith element is the price of ...

  8. LeetCode OJ 123. Best Time to Buy and Sell Stock III

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  9. leetcode:122. Best Time to Buy and Sell Stock II(java)解答

    转载请注明出处:z_zhaojun的博客 原文地址 题目地址 Best Time to Buy and Sell Stock II Say you have an array for which th ...

随机推荐

  1. MySQL 5.5 主从复制

    MySQL 5.5 主从复制的原理.过程   分为同步复制和异步复制,实际复制架构中大部分为异步复制.复制的基本过程如下:  1).Slave上面的IO进程连接上Master,并请求从指定日志文件的指 ...

  2. Fox

    Portal --> broken qwq Description 有n只狐狸在一起聚餐,每只狐狸都有一个年龄.按照狐狸们的习惯,坐在一起的两只狐狸的年龄之和需要是质数.现在这些狐狸们在一些圆桌 ...

  3. ORACLE获取某个时间段之间的月份列表

    返回1-31,或者1-12,或者某个 select rownum   from dual   connect by rownum<31 就是connect by http://marcospri ...

  4. java 注解详解

    先引用一下百度百科的名词解析: 定义:注解(Annotation),也叫元数据.一种代码级别的说明.它是JDK1.5及以后版本引入的一个特性,与类.接口.枚举是在同一个层次.它可以声明在包.类.字段. ...

  5. [DeeplearningAI笔记]卷积神经网络2.3-2.4深度残差网络

    4.2深度卷积网络 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文献 [残差网络]--He K, Zhang X, Ren S, et al. Deep Residual Learni ...

  6. lable标签的妙用

    最近在设计网页时,只要一加入表单或表单对象,文本框等等,就会在代码中加入一个<label></label>,一直没明白这个label是做什么的,今天正好看到了解释: Label ...

  7. Spring quartz定时任务service注入问题

    今天想单元测试一下spring中的quartz定时任务,job类的大致结构和下面的SpringQtz1类相似,我的是实现的org.quartz.Job接口,到最后总是发现job类里注入的service ...

  8. 改变你一生的编辑器:VSCode使用总结

    开发十年,只剩下这套Java开发体系了 >>>   前言:vscode是微软出品的,基于Electron和TypeScript的,现在已经是最火的一款文本编辑器.我认为vscode是 ...

  9. sweetAlert2

    SweetAlert2一个前端最好用的弹窗

  10. CSS属性的私有前缀

    在CSS属性能中,我们常常能看到-webkit-,-moz-之类的前缀,这种就叫做浏览器私有前缀,是浏览器对于新CSS属性的一个提前支持.-webkit-是webkit内核的,-moz-是Firefo ...