LeetCode解题报告—— Best Time to Buy and Sell Stock
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的更多相关文章
- 解题报告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 ...
- 【一天一道LeetCode】#122. Best Time to Buy and Sell Stock II
一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Say you ...
- 【LeetCode】188. Best Time to Buy and Sell Stock IV 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 【LeetCode】309. Best Time to Buy and Sell Stock with Cooldown 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 动态规划 日期 题目地址:https://leetc ...
- 【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 ...
- 【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 ...
- 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 ...
- 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 ...
- 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 ...
随机推荐
- Red Hat下升级python的问题
分为两部分: 一,升级Python 安装的包的渠道(传送门),安装过程的渠道(传送门). 二.涉及的问题 1.yum不能使用 解决办法(传送门),其中的部分就行.
- 51nod 1766 树上的最远点对(线段树)
像树的直径一样,两个集合的最长路也是由两个集合内部的最长路的两个端点组成的,于是我们知道了两个集合的最长路,枚举一下两两端点算出答案就可以合并了,所以就可以用线段树维护一个区间里的最长路了. #inc ...
- 线程同步API及它们的属性
头文件:<pthread.h> 编译记得加 -lpthread库 1:互斥锁(mutex) 1.1:互斥锁API 数据类型:pthread_mutex_t // 初始化一个互斥锁 int ...
- wordpress初始化安装
数据名,用户名,密码的选择: 从主机购买商的控制面板里面查询: 然后填入到WordPress数据库初始化页面..
- LeetCode-Insertion Sort List[AC源码]
package com.lw.leet5; /** * @ClassName:Solution * @Description: * Insertion Sort List * Sort a linke ...
- centos6.5 mqtt安装
CentOs 6.5 MQTT 安装部署 所需安装包: libwebsockets-v1.6-stable.tar.gz,mosquitto-1.4.8.tar.gz 1.安装依赖 # yum -y ...
- leetcode 刷题日志 2018-03-26
58. 最后一个单词的长度 分析:找最后一个非空格,向前找 int lengthOfLastWord(string s) { int i = s.find_last_not_of(' '); int ...
- 使用FormData提交表单及上传文件
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head ...
- Centos7环境下消息队列之ActiveMQ实战
Activemq介绍 对于消息的传递有两种类型: 一种是点对点的,即一个生产者和一个消费者一一对应: 另一种是发布/订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进行接收. JMS定义了 ...
- 解决gridview row 左边序列号 显示不完全的技巧
放在主程序 入口处, public Form1() { InitializeComponent(); gridView1.IndicatorWidth = ; //<宽度值>官方推荐常用是 ...