您将获得 n 天的 n 股票价格。输出可以通过交易股票获得的最大利润。您每天最多只能交易一次:每天您可以选择购买一只股票,或出售一只股票(如果有),或者放弃当天的交易而无所作为。
给出a = [1,2,10,9]
,返回16
说明:
您可以在第一天和第二天买入,在第三天和第四天卖出。
利润:-1-2 + 10 + 9 = 16
给出a = [9,5,9,10,5]
,返回5
说明:
您可以在第2天买入,在第4天卖出。
利润:-5 + 10 = 5
困难之处在于,您可以进行连续的买入和/或卖出,这意味着一旦拥有了股票,就不必在购买另一只股票之前就将其出售。
>我的想法是以下算法:
从最大价格开始,然后匹配输入数组中最大价格之前出现的最小价格。匹配后,从数组中删除这两个价格,并继续重复此过程,直到找不到更多匹配为止。该算法似乎可行,但是它花费的时间为 O(n 2 ),这不够快。
如何用更好的时间复杂度来解决此问题,例如 O(nlogn)?
答案 0 :(得分:9)
我们可以将其建模为最小成本流通问题,并通过类似于您的想法的专用O(n log n)-时间算法来最佳解决。
在流量网络中,每天有一个节点,一个代表市场的节点。每天有两个单位容量弧,一个来自市场的成本等于当日价格,一个到市场的成本等于负价格。零成本和无限容量的弧线可以将流量从每天(最后一天除外)转移到之后的一天。这些代表持股。
使用()
表示节点,==>
表示无限制容量弧,-->
表示单位容量弧,并标记成本,您的示例实例为
0 0 0
()======>()======>()======>()
^\ ^\ ^\ ^\
1| |-1 2| |-2 10| |-10 9| |-9
\v \v \v \v
( )
从技术上讲,这种重新制定公式可以在同一天进行买卖,但这不是有利可图的举动,所以没关系。
给定一个残差网络,该理论(线性规划对偶性)说,当且仅当没有负成本的简单循环时,我们才能完成。此类周期的直观含义正是您所期望的:购买股票并在以后出售它获利。
该算法的工作原理是,在k
的{{1}}到k
的头1
天内,连续消除所有负成本的简单周期(从现在开始是有利的周期)。在基本情况n
中,仅第一天就无法盈利,因此我们可以继续进行归纳。
对于归纳步骤,我们知道在头k = 1
天内没有获利周期,因此希望将其扩展到k-1
。如果在头k
天中有一个盈利周期,则涉及在第k
天卖出。但是买什么呢?我们可以通过保留我们的剩余购买机会的最低优先级队列来有效地回答该问题。我们将当天k
的价格与排队的分钟数进行比较,如果价格更高,我们会进行交易,这涉及弹出最低价并推动当天k
的价格,因为从残差网络的角度来看,稍后取消我们的销售与购买股票相同。然后,我们将当天k
的价格推高,以代表在一天k
实际购买的可能性。
我们在这里必须小心,并证明我们不仅在引入另一个有利可图的周期。那就是选择最低限价的原因:我们不能将新的“销售”(实际上是取消购买)机会与任何剩余的购买机会相结合,因为新的销售价格不高于任何这些机会。 >
完成的算法非常简单。在Python中:
k
答案 1 :(得分:2)
这是O(n²)算法。因此,从某种意义上讲,它不能以渐近的速度回答您的问题,但是正如您在注释中了解到的那样,算法是行不通的,我相信它仍然可能有用。
我去动态编程。重复这些天,并维护一个列表,其中索引描述您拥有的库存数量,并且该值是在这种情况下达到的最佳现金余额。因此,从清单[0]
开始,即一个条目表明您可以在余额为零的情况下拥有零库存。
每天,您可以购买,出售或跳过。您可以使用以下类似的方式表达所有内容:
balance_new[i] = max(balance[i], balance[i-1] - quote, balance[i+1] + quote)
第一个条目表示跳过:您保留当前库存和余额。第二个条目表示购买:您获得一只股票(从i-1
到i
),但余额减少了当天的价格。第三个条目是卖出:您将库存减少一倍,但将当前价格提高到余额。
从中获得的balance_new
将成为第二天的balance
。而且,您需要注意列表边界,在表达式边界之一处变得无效,因为它会超出范围,因此会引起注意。您无法通过购买操作达到零库存。经过一整天的处理,要求的最高利润为balance[0]
。它代表了没有库存的最大余额。
您有一个外循环,需要重复n天。以及一个内部循环,迭代您那时可能拥有的潜在股票数量。该数字在每次迭代中线性增长。如果您愿意的话,可以尝试变得更聪明,将内循环的步数减少一半,然后再将内循环的步数减少一。那是因为它永远不会花更多的钱购买股票。因此,内循环中的步数将从一个类似的值变为类似n / 2的内容,然后再次向下移动,总共为n²/ 4 + O(n),但总的来说仍为O(n²)。 / p>
答案 2 :(得分:0)
更正:我的逻辑失败了(对于[9,12,1,18,17,13,1,2,10]给出了29而不是35)...
这是我想出的逻辑: