【LeetCode】Best Time to Buy and Sell Stock IV
Best Time to Buy and Sell Stock IV
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 k transactions.
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
Credits:
Special thanks to @Freezen for adding this problem and creating all test cases.
[Solution]
这题如果一开始不重视 k 的条件限制,很容易误以为是一道简单的贪心题。
大概会想,无非就是找出序列中 所有的上升区段,并用上升区段的最后一个数减第一个数(即此上升区段的跨度)作为其 value,最后再取 前 k 个最大的 values 求和得解。
典型的贪心思想,我一开始这样想写的代码如下:(注意:一次交易是指一次买入和一次卖出操作,题目未说明清楚。)
class Solution:
# @return an integer as the maximum profit
def maxProfit(self, k, prices):
if prices == []:
return 0
down = prices[0]
up = prices[0]
ansList = []
for i in range(1, len(prices)):
if prices[i-1] < prices[i]:
up = prices[i]
elif prices[i] < prices[i-1]:
ansList.append(up - down)
down = prices[i]
up = prices[i]
ansList.append(up - down)
ansList.sort(reverse=True)
if k < len(ansList):
ans = sum(ansList[:k])
else:
ans = sum(ansList)
return ans
而且这贪心可以过:200 / 211 test cases passed.
但细想一下,正是因为有 k 的限制,其实 贪心 是不对的。
考虑这样一个样例:
Input: 2, [1,2,4,2,5,7,2,4,9,0]
如果用上面那段代码得出的结果会是:12,显然是取了 3~5 和 6~8 这两个区段(list下标号)。
但实际上,因为 k 限制在 2,所以可以有更优的解:0~5 和 6~8: 6+7=13。
这样,我们就找了一个反例证明贪心的不正确性(其实也不难直观的去想到)。
实际上,由于 k 的限制,使得决策之间产生了联系,决定了贪心的错误性。
很自然的,做决策求最值,会想到用 DP (动态规划)来完成这道题。
再来思考问题的本质,可以发现这样的特点:
买入和卖出操作是交替执行的,而且卖出之前一定得先买入。
转化为这样的一个数学问题:
给定一个序列,从该序列中找出一个元素保持在原序列中顺序并且元素个数是偶数的子序列,使得其偶数项之和与奇数项之和的差最大。
而对于每一天来说,只有两种选择,即选择 操作 或者 不操作。而具体的操作是买入还是卖出得由当前已经执行的操作数是奇偶性来决定。
所以我们可以从天数递增来地推上去直到第n天。
如果用 dp[j] 表示 完成第j次交易时 (由 j-1 转移到 j 必需伴随着一次操作)的最大收益,则状态转移方程可以写为:
dp[j] = max{dp[j], dp[j-1] + prices[i] * (j%2)?-1:1}
外循环 天数 i 从 0 递推到 size (第 j 次交易不一定发生在哪一天),内循环 j 从 1 递推到当前允许的最大操作数:min{2*k, i+1} (i 是 prices 中的 第 i+1 个元素)。
初始条件:dp[0] = 0,dp中的其他值为无穷小(None比任何数值都小)。
另外,有一个优化,当 2*k >= szie 时,k 的限制已经形同虚设了,操作数限制已经可以覆盖到每一天都允许操作,这种情况下还用上述DP效率太低,可以改为没有k限制的贪心版本(把所有上升区段跨度求和即为解)。
由于有了上述优化,所以用DP的情况一定是 2*k < size的情况,这种情况下 用完 2*k 次操作数限制所得的结果一定等于最优解(虽然不一定实际上进行2*k次操作,因为此时实际上放宽了题目限制条件,在同一个 i 值,dp[j]可能把这个 i 买入使得当前更优(因为初始值为无穷小),而到了dp[j+1]就把这个 i 卖出使得当前更优,实际上就相当于不操作,但记录的操作数 j 还是增加了2,所以实际上此时dp[j]表示的准确的实际含义是 最多完成j次交易时(实际可能不在j次时是最优),放大到全局即为 2*k 处最优。而又因为 i 是递推上去到 n 的,所以总会有找到 正确的最后一次交易使得在第 i 天dp[2*k]最大,而 i 再增加,操作数已经不能增加了(已经到了最大的限制)),所以最后的结果为 dp[2*k]。
最后AC代码:
class Solution:
# @return an integer as the maximum profit
def maxProfit(self, k, prices):
size = len(prices)
if k*2 >= size:
return self.noKLimit(size, prices)
dp = [None] * (2*k+1)
dp[0] = 0
for i in range(size):
for j in range(1, min(2*k, i+1)+1):
dp[j] = max(dp[j], dp[j-1]+prices[i]*[1, -1][j%2])
return dp[2*k] def noKLimit(self, size, prices):
sum = 0
for i in range(size - 1):
if prices[i+1]>prices[i]:
sum += prices[i+1] - prices[i]
return sum
注:一开始做的时候还没发现原来这是一个系列题,这是目前该系列最后一个(第四题),应该递进的来做可能比较简单。
参考:[LeetCode]Best Time to Buy and Sell Stock IV
【LeetCode】Best Time to Buy and Sell Stock IV的更多相关文章
- 【leetcode】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】Best Time to Buy and Sell Stock II
Best Time to Buy and Sell Stock II Say you have an array for which the ith element is the price of a ...
- 【leetcode】121-Best Time to Buy and Sell Stock
problem 121. Best Time to Buy and Sell Stock code class Solution { public: int maxProfit(vector<i ...
- 【LeetCode】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. If you were ...
- Java for LeetCode 188 Best Time to Buy and Sell Stock IV【HARD】
Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...
- [LeetCode] 188. Best Time to Buy and Sell Stock IV 买卖股票的最佳时间 IV
Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...
- 【数组】Best Time to Buy and Sell Stock I/II
Best Time to Buy and Sell Stock I 题目: Say you have an array for which the ith element is the price o ...
- [LeetCode][Java] Best Time to Buy and Sell Stock IV
题目: Say you have an array for which the ith element is the price of a given stock on day i. Design a ...
- 【leetcode】Best Time to Buy and Sell 3 (hard) 自己做出来了 但别人的更好
Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...
随机推荐
- HDUOJ----2571(命运)(简单动态规划)
命运 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submiss ...
- Play framework logging设置
play的logger是基于Log4j,Play 2.0 uses logback as its logging engine. 一.配置 1. 在conf/application.conf中设置lo ...
- thinkjs——空对象判断
使用thinkjs来做后台的项目开发时,总免不了进行一些数据的唯一性校验,比如说:有这么一个页面,需要对钢厂的名称做一个校验,于是自己在后台做条件搜索时,一不小心用到了两种方法: 一个是find(), ...
- freemarker小例子
1.在D盘下创建一个目录D:\\freemarker 2.在以上目录中放入一个模板文件test.ftl,内容如下: 第一个测试程序:${abc} 3.java代码如下(需要导入freemark ...
- 使用NuGet时的一个乌龙
问题描述 最近自己做的一个项目,计划开始使用NuGet来管理dll,但是遇到一个奇怪,但是结果证明是个乌龙的问题. 新建一个WebApi项目,使用NuGet管理第三方dll,其中有引用Newtonso ...
- apache本地网址配置
1 实现类似于域名访www.a.com问本地的空间,而不是放在apache下的htocs文件夹下,或者是wamp下的www文件下 2 首先修改C盘WINDOWS\system32\drivers\et ...
- X61的intel wireless 3945abg 不再掉线了
X61本的3945ABG无线网卡总是用一段时间就掉一次线(大约一个小时不到),换过两个路由器都这毛病. 今天有空,查了下,把网卡的“节约电源”去掉了,照样掉. 升级了驱动,掉的更勤了. 调整无线通道, ...
- [Js]无缝滚动
效果: 1.默认缓慢往左滚动 2.放到左箭头上还是向左滚动,放到右箭头上向右滚动 3.放到图片上停止滚动,移出继续滚动 思路: 1.计算图片列表ul的宽度 2.开启定时器,使其向左边距不断增大,造成向 ...
- 常见JS(JavaScript)冲突解决方法
1.一般JS冲突解决办法 a.最容易出现的就是js的命名冲突 ①.变量名冲突 变量有全局变量和局部变量当全局变量变量和局部变量名称一致时,就会js冲突,由于变量传递数值或地址不同就会产生JavaScr ...
- HTTP协议的chunked编码
一般情况HTTP的Header包含Content-Length域来指明报文体的长度.如: 有时候服务生成HTTP回应是无法确定消息大小的,比如大文件的下载,或者后台需要复杂的逻辑才能全部处理页面的请求 ...