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. arp 投毒实验

    1.查看kali2.0和kali2.0.0的IP地址,如图1和图2,其中192.168.1.133作为攻击者,192.168.1.109作为PC访问FTP服务器192.168.1.234 图1 图2 ...

  2. Codeforces 526.D Om Nom and Necklace

    D. Om Nom and Necklace time limit per test 1 second memory limit per test 256 megabytes input standa ...

  3. kotlin Hello World 以及关键字

    hello world:(支持函数式编程,不需要放到 class 中) fun main(args: Array<String>) { println("Hello World& ...

  4. php 修改图片分辨率

    <?php function resize_image($file, $w, $h, $crop=FALSE) { list($width, $height) = getimagesize($f ...

  5. 010. C++ 传值与传引用

    1.参数传递 参数传递:pass by value vs. pass by reference(to const) 推荐:能传引用,尽量传引用(高效,尤其在需要拷贝的对象很大时) class comp ...

  6. K8s仪表盘

    { "__inputs": [ { "name": "DS_TEST-ENVIORMENT-K8S", "label": ...

  7. 「Linux」VMware安装centos7(二)

    一.检查是否联网 命令:ping www.baidu.com 二.查询系统中的地址信息 命令:ip addr 三.查看当前网络连接 命令:nmcli connection show 四.设置网络连接 ...

  8. Ibatis的resultMap和查询数据的对应关系

    iBatis和MyBatis 中返回数据对应关系 直接进入主题,现在的项目改用MyBatis了,感觉跟iBatis还是不一样的,比如在判断空值上面,iBatis是有标签的<isNotEmpty& ...

  9. 游戏AI:行为树

    Behavior Tree 行为树通过子Task的返回值决定整棵树的走向 Task 行为树上的每个节点都称为一个Task, 每个Task存在三种状态, success, failure, runnin ...

  10. NYOJ 117 求逆序数 (树状数组)

    题目链接 描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 现在,给你一个N个元素的序列,请你判断出 ...