在股票价值数组中查找买入/卖出价格,以最大化正差
今天在面试中遇到这个问题,它的优化解决方案让我感到冷淡(这很打击,因为我真的很想为这家公司工作......)
给定一个实际值数组,每个数组都代表股票价值在任意一段时间后,找到一家公司的最佳买入价及其相应的最佳卖出价(低买高卖)。
为了举例说明,让我们以 Z 公司的股票代码为例
55.39 109.23 48.29 81.59 105.53 94.45 12.24
:请注意,数组是按时间“排序”的,即随着时间的推移,值会附加到数组的右端。因此,我们的买入价值将(必须)位于卖出价值的左侧。
(在上面的示例中,理想的解决方案是以 48.29
买入并以 105.53
卖出)
我用 O(n2 )复杂性(用java实现):
// returns a 2-element array: first element is the index in the argument array
// of the best buying price, and the second element is the index of the best
// selling price which, collectively, maximize the trading return
//
// if there is no favorable trading (e.g. prices monotonically fall), null is returned
public int[] maximizeReturn(ArrayList<Double> prices) {
int [] retval = new int[2];
int BUY = 0, SELL = 1;
retval[BUY] = retval[SELL] = -1; // indices of buy and sell prices, respectively
for (int i = 0; i < prices.size(); i++) {
for (int j = i + 1; j < prices.size(); j++) {
double difference = prices.get(j).doubleValue() -
prices.get(i).doubleValue();
if (difference > 0.0) {
if (retval[BUY] < 0 || difference > prices.get(retval[SELL]).doubleValue() -
prices.get(retval[BUY]).doubleValue()) {
retval[BUY] = i;
retval[SELL] = j;
}
}
}
}
return (retval[BUY] > 0 ? retval : null);
}
这就是我搞砸的地方:有一个线性时间O(n)解决方案,我在试图弄清楚它时完全失败了(是的,我知道, 失败)。有谁知道如何实现线性时间解决方案? (任何您熟悉的语言)谢谢!
编辑
我想,对于任何感兴趣的人来说,我今天刚刚收到消息,我没有得到我面试的工作,他们问我这个问题。 :(
Got this question in an interview today, and its optimized solution stopped me cold (which blows, because I really wanted to work for this company...)
Given a single array of real values, each of which represents the stock value of a company after an arbitrary period of time, find the best buy price and its corresponding best sell price (buy low, sell high).
To illustrate with an example, let's take the stock ticker of Company Z:
55.39 109.23 48.29 81.59 105.53 94.45 12.24
Important to note is the fact that the array is "sorted" temporally - i.e. as time passes, values are appended to the right end of the array. Thus, our buy value will be (has to be) to the left of our sell value.
(in the above example, the ideal solution is to buy at 48.29
and sell at 105.53
)
I came up with the naive solution easily enough with O(n2) complexity (implemented in java):
// returns a 2-element array: first element is the index in the argument array
// of the best buying price, and the second element is the index of the best
// selling price which, collectively, maximize the trading return
//
// if there is no favorable trading (e.g. prices monotonically fall), null is returned
public int[] maximizeReturn(ArrayList<Double> prices) {
int [] retval = new int[2];
int BUY = 0, SELL = 1;
retval[BUY] = retval[SELL] = -1; // indices of buy and sell prices, respectively
for (int i = 0; i < prices.size(); i++) {
for (int j = i + 1; j < prices.size(); j++) {
double difference = prices.get(j).doubleValue() -
prices.get(i).doubleValue();
if (difference > 0.0) {
if (retval[BUY] < 0 || difference > prices.get(retval[SELL]).doubleValue() -
prices.get(retval[BUY]).doubleValue()) {
retval[BUY] = i;
retval[SELL] = j;
}
}
}
}
return (retval[BUY] > 0 ? retval : null);
}
Here's where I screwed up: there's a linear time O(n) solution, and I completely bombed in trying to figure it out (yeah, I know, FAIL). Does anyone know how to implement the linear time solution? (any language you're comfortable with) Thanks!
Edit
I suppose, for anyone interested, I just received word today that I didn't get the job for which I interviewed where they asked me this question. :(
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(24)
在 C# 中:
编辑:基于 @Joe 失败测试用例的新算法 - Nice Catch BTW!这也与@Doug T 现在的答案相同......
In C#:
EDIT: New algo based on @Joe's failing test case -- Nice Catch BTW! It's also the same answer as @Doug T's now...
这是一个尝试(C++)。基本上每次我追踪一个新的顶部时,我都会尝试看看这是否是迄今为止最好的利润。我知道,“底部”肯定早就被发现了。那时我记得顶部、底部和当前的最大利润。如果稍后发现新的底部,那么它是在当前顶部之后,因此我们必须重置顶部,看看稍微较低的“顶部”是否可以产生更好的利润。
到目前为止,我已经使用了一堆不同的输入集,到目前为止我还没有遇到任何问题...(如果您测试这个并发现任何错误,请告诉我)
我强烈建议使用 Austin Salonen 对此问题的更新答案并根据您的语言进行调整。
Here's an attempt (C++). Basically everytime I track a new top, I try to see if thats the best profit thusfar. I know that the "bottom" must have been discovered earlier. At that point I remember the top, bottom, and the current max profit. If a new bottom is discovered later, its AFTER the current top, so we must reset top and see if a slightly lower "top" can yield better profit.
So far I've played around with a bunch of different input sets, and so far I haven't had any problems... (let me know if you test this and see anything wrong)
I highly recommend using Austin Salonen's updated answer to this question and adapting it to your language.
这个想法很简单。保留两个指针,lo 和 hi。
执行 Foor 循环
就这样
The idea is simple. Keep two pointers, lo and hi.
Do a Foor loop
That's it
以防万一您更喜欢这个答案。我在另一个网上找到了它,但仍然如此。
来源:http://leetcode.com/2010 /11/最佳买入和卖出股票时间.html
Just in case you prefer this answer. I found it in another web, but still.
source:http://leetcode.com/2010/11/best-time-to-buy-and-sell-stock.html
我真的必须指出,作为一个面试问题,希望你能解决它,因为 O(n) 是近乎荒谬的。面试问题旨在证明您可以解决问题,并且您能够解决它。事实上你用 O(N^2) 与 O(N) 解决它的事实应该是无关紧要的。如果一家公司因为不能在 O(N) 时间内解决这个问题而放弃雇用你,那么无论如何,这可能都不是你想要工作的公司。
I really have to point out as an interview question expecting you to solve it as O(n) is borderline absurd. Interview questions are meant to prove you can solve a problem, which you were able to solve it. The fact you solved it in O(N^2) vs O(N) should be irrelevant. If a company would pass over hiring you for not solving this in O(N) that's probably not a company you would have wanted to work at anyway.
我想描述一下我是如何解决这个问题的,以便更容易理解我的代码:
(1)对于每一天,如果我必须在那天出售我的股票,我可以支付的最低购买金额是多少它?本质上,我会跟踪那一天之前的最低价格
(2) 对于每一天,如果我在那天出售,我会赚多少钱? (当天的股价 - 最低价格)
这表明我必须跟踪两件事:(1)迄今为止的最低股价(2)迄今为止的最佳收益。
问题变成选择哪一天出售。我会在能给我带来最好收益的那一天出售。这是我的Java代码:
I'd like to describe how I approached this problem to make it easier to understand my code:
(1) For each day, if I had to sell my stock on that day, what would be the minimum amount I could have paid to buy it? Essentially, I'm keeping track of minimum price before that day
(2) For each day, if I were to sell on that day, how much am I earning? (Stock price on that day - minimum price)
This shows that I have to keep track of two things: (1) minimum stock price so far (2) best earning so far.
The problem becomes choosing which day to sell. I will sell on the day that will give me the best earning. Here is my Java code:
这是我的 O(n) 实现。我正在使用更改数组来计算最大利润以及买卖日期。
欢迎您对此发表评论。
Here is my O(n) implementation for this. I am using a change array to calculate the max profit and buy and sell dates.
Your comments on this are welcome.
在我努力学习 Go 的过程中,也为了在这方面绞尽脑汁,这是我的尝试。
In my effort to learn Go, and also to rake my brain on this one, here is my attempt.
这是我使用 Javascript 的尝试。该脚本以 O(N) 计算答案:
Here is my attempt using Javascript. The script computes the answer in O(N):
这是一个实际有效的 C 解决方案:
void bestBuySell()
{
双倍价格[] = {10.50, 10.0, 3.0, 194.0, 55.39, 2.0, 109.23, 48.29, 81.59, 105.53, 94.45, 191.0, 200.0, 12.24};
int 数组大小 = 14;
double bestBuy = 价格[0],bestSell = 价格[1],bestPotentialBuy = 价格[0];
双潜在利润 = 价格[1] - 价格[0];
}
This is a C solution that actually works:
void bestBuySell()
{
double prices[] = {10.50, 10.0, 3.0, 194.0, 55.39, 2.0, 109.23, 48.29, 81.59, 105.53, 94.45, 191.0, 200.0, 12.24};
int arrSize = 14;
double bestBuy = prices[0], bestSell = prices[1], bestPotentialBuy = prices[0];
double potentialProfit = prices[1] - prices[0];
}
1.我们不能简单地将数值中最小的金额作为“Best Buy”,最大的金额作为“Best Sell”,因为“Sell”必须在“Buy”之后发生。
2.我们不能将记录的最低值视为“百思买”,因为随后几天的股票价值可能与记录的最低值的差异可能产生的利润可能低于“记录的利润”。
3.Best Buy 和 Best Sell 被视为单一变量,因为正是这些值之间的正差才能产生最大利润。
4.由于过去任何记录的最低价都是潜在的买入候选者,因此必须始终根据记录的最低价和当天的股价检查最大利润条件。因此,我们始终必须跟踪记录的最低价,但只是存在由于原因 2,记录的最小值不构成“百思买”。
现在,下面的代码在 O(n) 次内执行将有意义。
}
1.We cant simply take the least amount among the values as " Best Buy" and the max amount as "Best Sell" because "Sell" has to happen after "Buy".
2.We must not treat the recorded minimum as the "Best Buy" because the subsequent days may have stock values whose difference with the recorded minimum may yield profit which could be less than the "recorded profit".
3.Best Buy and Best Sell is treated as a single variant,because it is the positive difference between these values that makes max profit.
4.Since any recorded minimum in the past is a potential candidate for buying,the max profit condition must always be checked against the recorded minimum and the current day's stock price.So we always have to keep track of recorded minimum,but just the presence of recorded minimum doesn't constitute "Best Buy" because of reason number 2.
Now have the below code which executes in O(n) times will make sense.
}
我针对这个问题提出了以下算法,似乎适用于所有输入。另外,如果股票价值持续下跌,程序会输出不购买该股票:
这有什么陷阱吗?时间复杂度为O(N)
I came up with following algorithm for this problem, seems to work for all inputs. Also, If the Stock value keeps droping, the program would output not to buy this stock:
Is there any catch you could find in this? It's time complexity is O(N)
这是我的解决方案,与@Doug T 相同,但我也在索引中跟踪这一天。请提供反馈。
Here is my solution, same as @Doug T. except I am also keeping track of the day in an index. Please provide feedback.
F# 解决方案适合那些对功能感兴趣的人。我不会说,虽然有那么大的不同。
输出:
F# solution for those who interested in functional take on this. I wouldn't say though it's that much different.
Output:
这是我在 Ruby 中的解决方案:
干杯
Here is my solution in Ruby:
Cheers
我得到了 100% 的同样的结果,给你。
I got 100% for the same, here you go.
我的想法是,对于每个指数
i
,出售这只股票的理想指数是什么?这当然是i
之后最大值的索引。这将我们的问题简化为在[1 ... n]
中为每个i
找到索引i
之后的最大元素如果我们可以这样做O(n)
时间,然后我们可以在其中找到最佳选择并报告它。一种方法是从数组末尾开始遍历,维护两个变量,一个保存我们迄今为止遇到的最大元素
max_till_now
,一个保存我们可以获得的最大利润到目前为止,盈利
。这只是为了让我们可以一次性完成此操作。我们还可以使用额外的空间,对于每个元素i
,存储其范围[i + 1 ... n]
中最大元素的索引,然后查找最大利润。这是我的Python代码:
The way I thought about this was, for every index
i
what would be the ideal index be for selling this stock? This is of course, the index of the maximum value afteri
. This reduces our problem to finding the maximum element after indexi
for eachi
in[1 ... n]
If we could do that inO(n)
time, then we could find the best choice amongst those and report it.A way to do this is to start traversing from the end of the array, maintaining two variables, one to save the largest element we have encountered so far
max_till_now
, and one to save the maximum profit we could get till now,profit
. This is just so that we can do this in one pass. We could also use extra space and for each elementi
, store the index of the largest element in the range[i + 1 ... n]
for it and then find the maximum profit.Here's my python code:
另一个 Ruby 解决方案:
Another Ruby solution:
那这个呢?
what about this?
JavaScript 中的解决方案
Solution in javascript
这是一个 javascript 解决方案。
运行时间是 O(n)
Heres a javascript solution..
Runtime on this is O(n)
scala 中的解决方案:
示例: [ 7, 2, 5, 6, 1, 3, 6, 4 ]
保留指向最后一个最低股票价格(lastStockPrice)的指针,并将其与当前股票价格进行比较。当你到达当前股价<最后最低股票价格,您更新lastStockPrice。
在循环数组时,跟踪 currentPrice 和 lastStockPrice 之间的最大差异(利润),因为当您更新 lastStockPrice 时,利润可能会发生变化。
下面的 scala 代码在 O(n) 时间内运行并占用恒定的空间。
Solution in scala :
Example : [ 7, 2, 5, 6, 1, 3, 6, 4 ]
Keep a pointer to the last minimum stock price(lastStockPrice) and compare it to the current stock price. When you reach a point where the current stock price < last minimun stock price, you update the lastStockPrice.
While looping through the array, keep a track of the max difference (profit) between the currentPrice and the lastStockPrice as the profit can change when you update the lastStockPrice.
The below scala code works in O(n) time and takes a constant amount of space.
解决这个问题的逻辑与使用 Kadane 算法的“最大子数组问题”相同。由于到目前为止还没有人提到这一点,我认为每个人都知道这是一件好事。
所有直接的解决方案都应该有效,但是如果面试官通过给出价格差异数组来稍微扭曲问题,例如:对于 {1, 7, 4, 11},如果他给出 {0, 6, -3, 7} ,您可能最终会感到困惑。
这里的逻辑是计算原始数组的差值(maxCur +=prices[i]-prices[i-1]),并找到给出最大利润的连续子数组。如果差值低于 0,则将其重置为零。
The logic to solve this problem is same as "max subarray problem" using Kadane's Algorithm. Since no body has mentioned this so far, I thought it's a good thing for everybody to know.
All the straight forward solution should work, but if the interviewer twists the question slightly by giving the difference array of prices, Ex: for {1, 7, 4, 11}, if he gives {0, 6, -3, 7}, you might end up being confused.
Here, the logic is to calculate the difference (maxCur += prices[i] - prices[i-1]) of the original array, and find a contiguous subarray giving maximum profit. If the difference falls below 0, reset it to zero.