LeetCode - Best Time To Buy and Sell Stock Series (I, II, III, IV, with Cooldown)
来源:互联网 发布:诉苦大会 知乎 编辑:程序博客网 时间:2024/05/16 17:22
LeetCode - Best Time to Buy and Sell Stock 系列 解题报告
本文记录笔者在解LeetCode上的Best Time to Buy and Sell Stock系列时的一些想法。该系列题目共有五道,它们背景相似,但因为条件限制不同,解决思路也不太相同。
I
Best Time to Buy and Sell Stock
https://leetcode.com/problems/best-time-to-buy-and-sell-stock/
题目大意是,给定一个关于每天股票价格的序列,只能买卖一次,求最大利润。
我首先想到的是求相邻两天的价格的差值,然后求这个关于差值的数列的最大子数列(53. Maximum Subarray)。
具体思路是DP,让dp[i]为以第i个元素为结尾的最大的子数列,那么有,
这可以在
class Solution(object): def maxProfit(self, prices): arr=[] curr_max=0 last_max=0 for i in range(len(prices)-1): curr=prices[i+1]-prices[i] if last_max > 0: last_max += curr else: last_max = curr curr_max = max(curr_max,last_max) return curr_max
后来看了其他人的答案,其实这可以用全局最优和局部最优的角度去考虑。如下面重写的代码中glo(bal)全局最优只有在小于loc(al)局部最优时才会被更新。当局部最优某天小于0,说明新的最低点发现了,这时候可以将局部最优置为0,说明局部最优的买入点要更新成这个新的最低点了。
这同样是
class Solution(object): def maxProfit(self, prices): glo=0 loc=0 for i in range(1,len(prices)): delta = prices[i]-prices[i-1] loc += delta if loc < 0: loc = 0 if loc > glo: glo = loc return glo
II
Best Time to Buy and Sell Stock II
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/
这也是给定了一个价格的序列,只不过允许任意次数的交易。
这个就很简单了,既然不限次数,那么每个相邻交易日,能赚的都赚了。
class Solution(object): def maxProfit(self, prices): """ :type prices: List[int] :rtype: int """ result=0 for i in range(len(prices)-1): d=prices[i+1]-prices[i] if d > 0: result+=d return result
III
Best Time to Buy and Sell Stock III
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/
这道题的限制是,最多只能买卖两次。
我的做法是求所有[0, …, i]的子数列只买卖一次的大小,做法和Best Time to Buy and Sell Stock I 是一样的,结果放在pre[i]中。这个只需要扫描一遍整个数组即可。
再求所有[i, …, n-1]的子数列只买卖一次的大小,这个做法和上面的是相似的,只不过我们要从n-1开始,倒着扫描数组,并每次记录最糟糕的买卖情况(因为倒序买卖的最差情况,就对应着正序买卖的最好情况)。结果放在post[i]中。
上面两个过程都是
class Solution(object): def maxProfit(self, prices): if len(prices) == 0 or len(prices) == 1: return 0 pre = [0 for i in range(0, len(prices))] post = [0 for i in range(0, len(prices))] glo = 0 loc = 0 for i in range(1, len(prices)): loc += prices[i] - prices[i - 1] if loc < 0: loc = 0 glo = max(glo, loc) pre[i] = glo glo = 0 loc = 0 for i in range(len(prices)-1,0,-1): loc += prices[i-1]-prices[i] if loc > 0: loc = 0 glo = min(glo,loc) post[i-1] = - glo print(pre) print(post) curr = max(pre[len(prices)-1],post[0]) for i in range(1,len(prices)-1): curr = max(curr,pre[i]+post[i+1]) return curr
IV
Best Time to Buy and Sell Stock IV
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/
这次的限制是,最多可以做k次买卖。
这个我就不会了,后来参考了一下网上的解法。
Best Time to Buy and Sell Stock III – LeetCode
http://blog.csdn.net/linhuanmars/article/details/23236995
这里介绍的解法就是DP,但状态的定义比较巧妙。总体思路也是一种局部最优、全局最优的方法。
global[i][j]表示前i天最多做j次买卖的全局最优值,local[i][j]表示前i天最多做j次买卖且第i天是需要卖出的。
它们的关系,有
这条式子是以第i天是否有卖出动作作为标准的。
其中diff是第i天和i-1天的差价。
这个算法时间复杂度是O(nk),如果令k=2可以直接获得第III的解法。
class Solution(object): def maxProfit(self, k, prices): if len(prices) == 0 or len(prices) == 1: return 0 if k == 0: return 0 if k >= len(prices): acc = 0 for i in range(1,len(prices)): if prices[i] - prices[i-1] > 0: acc += prices[i]-prices[i-1] return acc glo = [[0, 0] for i in range(len(prices))] loc = [[0, 0] for i in range(len(prices))] # j == 1 best = 0 loc_maxima = 0 for i in range(1, len(prices)): delta = prices[i] - prices[i - 1] loc_maxima += delta if loc_maxima < 0: loc_maxima = 0 best = max(best, loc_maxima) loc[i][1] = loc_maxima glo[i][1] = best # j > 1 for j in range(2, k + 1): for i in range(1, len(prices)): diff = prices[i] - prices[i - 1] loc[i][j%2] = max(glo[i - 1][(j - 1)%2] + max(diff, 0), loc[i - 1][j%2] + diff) glo[i][j%2] = max(loc[i][j%2], glo[i - 1][j%2]) print(glo) print(loc) return glo[len(prices) - 1][k%2]
with Cooldown
Best Time to Buy and Sell Stock with Cooldown
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldow/
这道题的要求是,允许做任意多次交易,但在做卖出操作后的一天,是不能在做买入了,是为cooldown。
我一开始写了个贪心,但这是错的(我太天真了)。
后来我参考了这里,
Share my thinking process
https://discuss.leetcode.com/topic/30421/share-my-thinking-process
恰好该文作者也是该题目的作者。
解答用的是DP,定义了三种状态buy[],sell[]和rest[]。
先说明一下,所谓的交易序列就是类似于[buy, sell, rest, buy, rest …]的序列,其中元素分别代表该天做的动作。我们不用担心会出现在同一天出现buy和sell,因为这不能带来利润,且还带来额外的cooldown限制。
buy[i]的意思是,从第0天到第i天里面所有的以buy为结尾的交易序列中的最优解(最大利润),比如[buy,sell,buy],[rest,rest,buy]。注意[buy, rest, rest]也可以算这种序列。这里会让人产生疑惑,这和rest[i]不就冲突了吗,我们待会再看。
sell[i]和rest[i]意思是类似的。
那么这里就有状态转移,
buy[i]代表的最优解,可以从第i天是否买入来分类。换言之,比较从rest[i-1]代表的最优解减去i天价格,和第i天不做买入操作(rest)的结果。buy[i-1]代表的交易序列其实也是满足buy[i]的交易序列的要求的,因为序列最后一个操作还是buy(忽略尾带的 rest)。
sell[i]代表的最优解,同理,从第i天是否发生卖出操作分类。
rest[i]就随意多了,第i天肯定不能是buy或者sell,只能是rest。那么从0到i-1天无论什么序列,都是符合要求的。
针对前面rest可能带有的冲突、冗余的“属性”,作者后面又很敏锐地指出,rest[i]其实就等于sell[i-1]!这是因为rest[i]一定大于等于buy[i],而sell[i-1]又大于等于rest[i]。因此上面的第三个等式其实可以直接记作,rest[i]=sell[i-1]。同样的,第一个等式的rest[i-1]-price也可以改写成sell[i-2]-price了。
最后,只要设置好初始量,最后迭代到最后一天即可。而初始量,可以考虑
buy[-1] = - prices[0]
sell[-1] = 0
buy[0] = - prices[0]
sell [0] = 0
设置 -1 下标主要是因为buy[i]需要用到sell[i-2]。
class Solution(object): def maxProfit(self, prices): """ :type prices: List[int] :rtype: int """ if len(prices) == 0: return 0 prev_buy = - prices[0] prev_sell = 0 buy = -prices[0] sell = 0 for i in range(1,len(prices)): new_buy = max(buy,prev_sell-prices[i]) new_sell = max(sell,buy+prices[i]) prev_sell = sell prev_buy = buy sell = new_sell buy = new_buy return max(buy,sell)#print(Solution().maxProfit([1,2,3,0,2]))
- LeetCode - Best Time To Buy and Sell Stock Series (I, II, III, IV, with Cooldown)
- 分类一:Best Time to Buy and Sell Stock I/ II/ III/ IV/ with Cooldown
- 【LeetCode从零单刷】Best Time to Buy and Sell Stock I, II, With Cooldown
- LeetCode OJ Best Time to Buy and Sell Stock I II III IV
- LeetCode - Best Time to Buy and Sell Stock I && II && III && IV
- 【LeetCode】 Best Time to Buy and Sell Stock I II III IV 解题报告
- LeetCode-Best Time to Buy and Sell Stock I II III IV
- 【LeetCode】 Best Time to Buy and Sell Stock I II III IV 解题报告
- [LeetCODE] Best Time to Buy and Sell Stock I II III IV V
- leetcode笔记--Best Time to Buy and Sell Stock系列(I,II, III, IV)
- [LeetCode] Best Time to Buy and Sell Stock I II III IV
- [LeetCode] Best Time to Buy and Sell Stock I II III IV 股票买卖
- 【LeetCode】 best-time-to-buy-and-sell-stock-i ii iii iv
- [Leetcode] #121#122#123#188 Best Time to Buy and Sell Stock I & II & III & IV
- LeetCode Best Time to Buy and Sell Stock I & II & III & IV
- leetcode Best Time to Buy and Sell Stock with Cooldown
- LeetCode Best Time to Buy and Sell Stock with Cooldown
- Leetcode: Best Time to Buy and Sell Stock with Cooldown
- css贯穿 嵌套
- angular基础3
- 1036. Boys vs Girls (25)解题报告
- XILINX资源获取
- 性能测试 工具(二)
- LeetCode - Best Time To Buy and Sell Stock Series (I, II, III, IV, with Cooldown)
- 使用Vtamio 5.02版本在真机运行遇到 LOAD FFMPEG ERROR: 的解决办法
- 解决WPF的ScrollViewer在使用触摸屏时,滑到尽头窗口抖动的情况
- Java 初始化顺序
- 配置Eclipse的hadoop-eclipse-plugin.jar(自学随笔)
- JavaScript 函数
- JAVAWEB-JSTL
- Merge Two Sorted Lists (EASY)
- HTML实现二级菜单