今天在接受采访时得到了这个问题,其优化的解决方案让我感到很冷淡(因为我真的很想为这家公司工作......)
给定一组实际值,每个值代表一个公司在任意一段时间后的股票价值,找到最佳买入价及其相应的最佳卖出价(买入低价,卖出高价)。
举一个例子来说明一下,让我们来看看Z公司的股票代码:
55.39 109.23 48.29 81.59 105.53 94.45 12.24
值得注意的重要事项是阵列在时间上“排序” - 即随着时间的推移,值被附加到阵列的右端。因此,我们的买入价值将(必须)在卖出价值的左侧。
(在上面的示例中,理想的解决方案是在48.29
处购买并在105.53
处出售)
我很容易想出O(n 2 )的复杂性(在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)解决方案,我完全轰炸试图解决它(是的,我知道,失败)。有谁知道如何实现线性时间解决方案? (你喜欢的任何语言)谢谢!
修改
我想,对于任何有兴趣的人,我今天刚收到的消息是,我没有得到我在他们问我这个问题时所采访的工作。 :(
答案 0 :(得分:14)
在C#中:
static void Main(string[] args)
{
double[] values = new double[7]{55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24};
double max = double.MinValue, maxDiff = double.MinValue, diff = 0;
for (int i = 1; i < values.Length; i++)
{
if (values[i] > values[i - 1])
{
//trending upward, append to existing differential
diff += values[i] - values[i - 1];
}
else
{
//trending downward, reset the diff
diff = 0;
}
if (diff > maxDiff)
{
maxDiff = diff;
max = values[i];
}
}
Console.WriteLine("Buy at {0}; Sell at {1}", max - maxDiff, max);
}
编辑:基于@ Joe失败测试案例的新算法 - Nice Catch BTW!这也和@Doug T现在的答案相同......
static void Main(string[] args)
{
double[] values = new double[8] { 55.39, 109.23, 48.29, 81.59, 81.58, 105.53, 94.45, 12.24 };
double max = double.MinValue, maxDiff = double.MinValue, diff = 0;
double bottom = values[0];
for (int i = 1; i < values.Length; i++)
{
diff += values[i] - values[i - 1];
if (diff > maxDiff)
{
maxDiff = diff;
max = values[i];
}
if (values[i] < bottom)
{
bottom = values[i];
diff = 0;
}
}
Console.WriteLine("Buy at {0}; Sell at {1}", max - maxDiff, max);
}
答案 1 :(得分:9)
这是一次尝试(C ++)。基本上每当我追踪一个新的顶部,我试着看看这是否是最好的利润。我知道必须先发现“底部”。那时我记得顶部,底部和当前的最大利润。如果稍后发现新的底部,它在当前顶部之后,那么我们必须重置顶部并查看略低的“顶部”是否可以产生更好的利润。
#include <iostream>
int main()
{
double REALLY_BIG_NO = 1e99;
double bottom = REALLY_BIG_NO; // arbirtrary large number
double currBestBuy = 0.0;
double top = 0.0;
double currBestSell = 0.0;
double profit = 0.0;
// array of prices
double prices[] = {10.50, 55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24, 152.0, 2, 170.0};
int numPrices = 10;// number of prices
for (int i = 0; i < numPrices; ++i)
{
if (prices[i] < bottom)
{
bottom = prices[i];
// reset the search on a new bottom
top = 0.0;
}
else if (prices[i] > top)
{
top = prices[i];
// calculate profit
double potentialProfit = (top - bottom);
if (potentialProfit > profit &&
bottom != REALLY_BIG_NO)
{
profit = potentialProfit;
currBestSell = top;
currBestBuy = bottom;
}
}
}
std::cout << "Best Buy: " << currBestBuy << "Best Sell: " << currBestSell << std::endl;
}
到目前为止,我已经玩了很多不同的输入集,到目前为止我没有遇到任何问题......(如果你测试这个并且看错了,请告诉我)
我强烈建议您使用 Austin Salonen 对此问题的最新回答,并根据您的语言进行调整。
答案 2 :(得分:2)
这个想法很简单。保持两个指针,lo和hi。
做一个Foor循环
def getBestProfit(prices):
lo = hi = profit = 0
for price in prices:
if lo == 0 and hi == 0:
lo = hi = price
if price > hi:
hi = price
if price < low:
tmpProfit = hi - lo
if tmpProfit > profit:
profit = tmpProfit
lo = hi = price
return profit
就是这样
答案 3 :(得分:2)
void getBestTime (int stocks[], int sz, int &buy, int &sell){
int min = 0;
int maxDiff = 0;
buy = sell = 0;
for (int i = 0; i < sz; i++)
{
if (stocks[i] < stocks[min])
{
min = i;
}
int diff = stocks[i] - stocks[min];
if (diff > maxDiff)
{
buy = min;
sell = i;
maxDiff = diff;
}
}}
以防你喜欢这个答案。我在另一个网站上找到了它,但仍然。 源:http://leetcode.com/2010/11/best-time-to-buy-and-sell-stock.html
答案 4 :(得分:1)
public void profit(float stock[], int arlen ){
float buy = stock[0];
float sell = stock[arlen-1];
int bi = 0;
int si = arlen - 1;
for( int i = 0; i < arlen && bi < si ; i++){
if( stock[i] < buy && i < si){
buy = stock[i];
bi = i;
}
if(stock[arlen - i - 1] > sell && (arlen - i -1) > bi){
sell = stock[arlen - i - 1];
si = arlen - i - 1;
}
}
System.out.println(buy+" "+sell);
}
答案 5 :(得分:0)
解决此问题的逻辑与使用 Kadane 算法的“最大子数组问题”相同。由于到目前为止还没有任何机构提到这一点,我认为每个人都知道这是一件好事。
所有直截了当的解决方案都应该有效,但如果面试官通过给出价格差异数组稍微扭曲问题,例如:对于 {1, 7, 4, 11},如果他给出 {0, 6, -3 , 7},你最终可能会感到困惑。
这里的逻辑是计算原始数组的差值 (maxCur +=prices[i] -prices[i-1]),并找到一个连续的子数组,给出最大的利润。如果差值低于 0,则将其重置为零。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
_currmax = 0
_globalMax = 0
for i in range(1,len(prices)):
_currmax = max(_currmax+(prices[i]-prices[i-1]),0)
_globalMax = max(_globalMax,_currmax)
return _globalMax
答案 6 :(得分:0)
scala中的解决方案:
示例:[7,2,5,6,1,3,6,4]
保持指向最后一个最低股票价格(lastStockPrice)的指针,并将其与当前股票价格进行比较。当您达到当前股票价格<1的点时最后的最小股票价格,你更新lastStockPrice。
在循环遍历数组时,跟踪currentPrice和lastStockPrice之间的最大差异(利润),因为更新lastStockPrice时利润可能会发生变化。
以下scala代码在O(n)时间内工作并占用一定量的空间。
object Solution {
def maxProfit(prices: Array[Int]): Int = {
var lastStockPrice = Int.MaxValue
var maxProfit = 0
for(currentPrice <- prices){
if(currentPrice < lastStockPrice){
lastStockPrice = currentPrice;
}else if(currentPrice - lastStockPrice > maxProfit){
maxProfit = currentPrice - lastStockPrice;
}
}
maxProfit
}
}
答案 7 :(得分:0)
这是一个javascript解决方案..
function getMax(arr){
//we need more than at least 3 ints to be able to do this
if(arr.length <= 1) return arr;
// get the minimum price we can sell at to make a profit
var min = arr[0];
//get the first potential maximum profit
var max = arr[1] - arr[0];
//while looping through we must get a potential value,
//we can then compare that using the math.max using the maximum
//and the potential prices that we have seen. Once the loop runs the ouput here should be 6!
for(var i = 1; i < arr.length; ++i){
var current = arr[i];
var potential = current - min;
max = Math.max(max, potential);
min = Math.min(min, current);
}
return max;
}
console.log(getMax([10, 7, 5, 8, 11, 9]));
此时的运行时间为O(n)
答案 8 :(得分:0)
javascript中的解决方案
var stockArr = [13931, 9889, 987, 4, 89, 100];
function getBestTime(sortedArr) {
var min = 0;
var buyIndx = 0;
var saleIndx = 0;
var maxDiff = 0;
for (var i = 0; i < stockArr.length; i++) {
if (stockArr[i] < stockArr[min]) {
min = i;
}
var diff = stockArr[i] - stockArr[min];
if (diff > maxDiff) {
buy = min;
sale = i;
maxDiff = diff;
}
}
return {
buy:buy+1,
sale:sale+1,
diff:maxDiff
}
}
console.log(getBestTime(stockArr));
答案 9 :(得分:0)
这是怎么回事?
min = 100000000
max = 0
for elem in inp:
if elem < min:
min = elem
tempMax = elem-min
if tempMax > max:
max = tempMax
print(max)
答案 10 :(得分:0)
另一个Ruby解决方案:
# Here's some examples. Please feel free to give your new test.
values = [55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24]
# values = [5, 6, 4, 7, 9, 8, 8]
# values = [5, 10, 4, 6, 7]
# values = [5, 10, 4, 6, 12]
# values = [1, 2, 3, 4, 5]
# Initialize parameters.
min = values[0]
best_buy_time = values[0]
best_sell_time = values[0]
max_profit = 0
# This solution is based on comparing previous k elements and k+1 one.
# The runtime is O(n) and it only use O(1) auxiliary storage.
values.each_with_index do |value, index = 1|
# Check value in this turn.
puts value
# Check current value is bigger than min or not.
# If not, we find the new min.
if value <= min
min = value
# If current value is bigger than min and
# (value - min) is bigger than previous max_profit,
# set new best_buy_time, best_sell_time & max_profit.
else
if value - min >= max_profit
best_buy_time = min
best_sell_time = value
max_profit = value - min
end
end
end
# Let's see about the result.
puts "\nbest_buy_time: ", best_buy_time, "\nbest_sell_time: ", best_sell_time, "\nmax_profit: ", max_profit
答案 11 :(得分:0)
我对此的看法是,对于每个指数i
,出售此股票的理想指数是什么?这当然是i
之后的最大值的索引。这减少了我们在i
中为每个i
找到索引[1 ... n]
之后的最大元素的问题。如果我们可以在O(n)
时间内完成,那么我们可以找到最佳选择那些并报告。
这样做的一种方法是从数组的末尾开始遍历,维护两个变量,一个用于保存我们到目前为止遇到的最大元素max_till_now
,另一个用于保存我们可以获得的最大利润到现在为止,profit
。这只是为了让我们可以一次完成。我们还可以使用额外的空间,并为每个元素i
存储[i + 1 ... n]
范围内最大元素的索引,然后找到最大利润。
这是我的python代码:
def buyLowSellHigh(L):
length = len(L)
profit = 0
max_till_now = L[length - 1]
for i in xrange(length - 2, -1, -1):
if L[i] > max_till_now: max_till_now = L[i]
else:
if max_till_now - L[i] > profit: profit = max_till_now - L[i]
return profit
答案 12 :(得分:0)
我得到了同样的100%,你走了。
public int solution(int[] A) {
if (A == null || A.length<=1){
return 0;
}
int minValue = Math.min(A[0], A[1]);
int profit = A[1] - A[0];
for (int i = 2; i < A.length; i++) {
minValue = Math.min(minValue, A[i]);
profit = Math.max(A[i] - minValue,profit);
}
return profit > 0 ? profit : 0;
}
答案 13 :(得分:0)
这是我在Ruby中的解决方案:
values = [55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24]
max_diff = 0
diff = 0
min = values[0]
max = 0
values.each_with_index do |value, index = 1|
# get an array of the previous values before the current one
lag_values = values[0..index]
# get the minimum of those previous values
min_lag_value = lag_values.min
# difference between current value and minimum of previous ones
diff = values[index].to_i - min_lag_value.to_i
# if current difference is > previous max difference, then set new values for min, max_diff, and max
if diff > max_diff
max_diff = diff
min = min_lag_value
max = values[index]
end
end
min # => 48.29
max # => 105.3
max_diff # => 57
干杯
答案 14 :(得分:0)
F#解决方案适合那些对功能感兴趣的人。我不会说虽然它有很大的不同。
let start, _, profit =
[55.39; 109.23; 48.29; 81.59; 81.58; 105.53; 94.45; 12.24 ]
|> Seq.fold (fun (start,newStart,profit) i ->
let start = defaultArg start i
let newStart = defaultArg newStart i
let newProfit = i - newStart
if profit < newProfit
then Some newStart, Some newStart,newProfit
else if start > i
then Some start, Some i, profit
else Some start,Some newStart,profit) (None,None, 0.0)
printf "Best buy: %f; Best sell: %f" start.Value (start.Value + profit)
输出:
Best buy: 48.290000; Best sell: 105.530000
答案 15 :(得分:0)
这是我的解决方案,与@Doug T.相同,除了我还跟踪索引中的日期。请提供反馈。
int prices[] = {4,4,5,6,2,5,1,1};
//int prices[] = {100, 180, 260, 310, 40, 535, 695};
int currentBestSellPrice=0;
int currentBestBuyPrice=0;
int lowindex=0;
int highindex=0;
int low=prices[0];
int high=prices[0];
int profit=0;
int templowindex=0;
for(int i=0; i< prices.length;i++)
{
// buy low
if(prices[i] < low && i+1 < prices.length)
{
low = prices[i];
templowindex=i;
high=0;
}
// sell high
else if(prices[i] > high)
{
high = prices[i];
int potentialprofit = (high-low);
if(potentialprofit > profit)
{
profit = potentialprofit;
currentBestSellPrice = high;
currentBestBuyPrice = low;
highindex=i;
lowindex=templowindex;
}
}
}
System.out.println("Best Buy Price : "+ currentBestBuyPrice + " on day "+ lowindex);
System.out.println("Best Sell Price : "+ currentBestSellPrice+ " on day "+ highindex );
答案 16 :(得分:0)
我想出了这个问题的以下算法,似乎适用于所有输入。此外,如果股票价值持续下跌,程序将输出不购买此股票:
public class GetMaxProfit
{
double minValue = -1, maxValue = -1;
double maxDiff = 0;
public void getProfit(double [] inputArray){
int i=0, j=1;
double newDiff = 0;
while(j<inputArray.length){
newDiff = inputArray[j]-inputArray[i];
if(newDiff > 0){
if(newDiff > this.maxDiff){
this.minValue = inputArray[i];
this.maxValue = inputArray[j];
this.maxDiff = newDiff;
}
}
else{
i = j;
}
j++;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
GetMaxProfit obj = new GetMaxProfit();
obj.getProfit(new double[]{55.39, 19.23, 14.29, 11.59, 10.53, 9.45, 1.24});
if(obj.minValue != -1 && obj.maxValue != -1){
System.out.println("Buy Value for the input: "+obj.minValue);
System.out.println("Sell Value for the input: "+obj.maxValue);
System.out.println("Best profit for the input: "+obj.maxDiff);
}
else
System.out.println("Do Not Buy This STOCK!!);
}
}
你能找到任何捕获物吗?它的时间复杂度是O(N)
答案 17 :(得分:0)
1.我们不能简单地将价值中的最小金额作为“百思买”,最大金额作为“最佳卖出”,因为“卖出”必须在“买入”之后发生。
2.我们不得将记录的最低数量视为“百思买”,因为随后的日子可能有股票价值,其与记录的最低价格的差异可能产生的利润可能低于“记录的利润”。
3.Best Buy和Best Sell被视为单一变体,因为这些价值之间的正差异使得最大利润。
4.由于过去记录的最小值是潜在的买入候选人,因此必须始终根据记录的最小值和当天的股票价格检查最大利润条件。因此,我们始终必须跟踪记录的最小值,但是由于原因2,只是记录最小值的存在不构成“百思买”。
现在让下面的代码在O(n)次执行是有意义的。
public class BestStockBuyAndSell {
public static void main(String[] args) {
double[] stockPrices = {55.39,109.23,48.29,81.59,105.53,94.45,12.24};
int [] bestBuySellIndex = maxProfit(stockPrices);
System.out.println("Best Buy At "+stockPrices[bestBuySellIndex[0]]);
System.out.println("Best Sell At "+stockPrices[bestBuySellIndex[1]]);
System.out.println("Max Profit = "+(stockPrices[bestBuySellIndex[1]]-stockPrices[bestBuySellIndex[0]]));
}
public static int[] maxProfit(double[] stockPrices)
{
int bestBuy=0;
int bestSell=0;
int[] bestCombination ={bestBuy,bestSell};
double recordedMinimum = stockPrices[bestBuy];
int recordedMinimuIndex = bestBuy;
double bestProfitSofar = stockPrices[bestSell] - stockPrices[bestBuy];
for(int i=1;i<stockPrices.length;i++)
{
if(stockPrices[i] - recordedMinimum > bestProfitSofar)
{
bestProfitSofar = stockPrices[i] - recordedMinimum;
bestSell = i;
bestBuy = recordedMinimuIndex;
}
if(stockPrices[i] < recordedMinimum)
{
recordedMinimuIndex = i;
recordedMinimum = stockPrices[i];
}
}
bestCombination[0] = bestBuy;
bestCombination[1] = bestSell;
return bestCombination;
}
}
答案 18 :(得分:0)
这是一个实际有效的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 arrSize = 14; double bestBuy = price [0],bestSell = price [1],bestPotentialBuy = price [0]; double potentialProfit =价格[1] - 价格[0];
for(int i = 1; i < (arrSize-1); i++)
{
if(prices[i] < bestBuy)
bestPotentialBuy = prices[i];
if((prices[i+1] - bestPotentialBuy) > potentialProfit)
{
bestBuy = bestPotentialBuy;
bestSell = prices[i+1];
potentialProfit = prices[i+1] - bestPotentialBuy;
}
}
printf( "bestBuy %f bestSell %f\n", bestBuy, bestSell );
}
答案 19 :(得分:0)
这是我尝试使用Javascript。脚本在O(N)中计算答案:
//Main Stock Array
var stock = [15, 20, 0, 3, 30, 45, 67, 92, 1, 4, 99];
//Setup initial variable state
var ans = {}, tmp = {}; //These are just for namespacing / syntatic sugar
ans.minVal = stock[0];
ans.minInd = 0;
ans.maxDiff = stock[1] - stock[0];
ans.maxInd = 1;
tmp.minInd = ans.minInd;
tmp.minVal = ans.minVal;
//Basically we iterate throught the array. If we find a new low, we start tracking it. Otherwise we compare the current index against the previously found low
for(i = 1; i <= stock.length-1; i++) {
if(tmp.minVal > stock[i]) {
tmp.minVal = stock[i];
tmp.minInd = i;
} else {
ans.diff = stock[i] - stock[tmp.minInd];
if(ans.diff > ans.maxDiff) { //Looks like we found a new maxDifference. Lets log the indexes
ans.maxDiff = ans.diff;
ans.maxInd = i;
ans.minInd = tmp.minInd;
ans.minVal = tmp.minVal;
}
}
}
document.write('You should buy your stocks on day ' + ans.minInd + ' and sell on day ' + ans.maxInd);
答案 20 :(得分:0)
在我学习围棋的过程中,以及在这一方面嘲笑我的脑子,这是我的尝试。
func GetMaxProfit2(prices []float64) (float64, float64) {
var min, max, pmin, pmax int
for i, v := range prices {
if v - prices[min] > prices[max] - prices[min] {
pmax = max
max = i
}
// Reset the max when min is updated.
if v < prices[min] {
pmin = min
min = i
pmax = max
max = i
}
}
// If min is ahead of max, reset the values back
if min >= max {
min = pmin
max = pmax
}
return prices[min], prices[max]
}
答案 21 :(得分:0)
这是我的O(n)实现。我正在使用更改数组来计算最大利润以及买卖日期。 欢迎您对此发表评论。
#include<stdafx.h>
#include<stdio.h>
int main()
{
//int arr[10] = {15, 3, 5,9,10,1,6,4,7,2};
int arr[7] = {55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24};
int change[7];
int n=7;
for(int i=1;i<=n;i++)
{
change[i] = arr[i]- arr[i-1];
}
int i=0,index = 0;
int sum = 0;
int maxsum = 0;
int startpos = 0;
int endpos = 0;
while(index < n)
{
sum = sum + change[index];
if(maxsum < sum)
{
maxsum = sum;
startpos = i;
endpos = index;
}
else if (sum<0) // negative number ,set sum to zero
{
sum = 0;
i=index+1;
}
index++;
}
printf("max profit is%d %d %d", maxsum , startpos, endpos+1 );
}
答案 22 :(得分:0)
我想描述一下我是如何处理这个问题的,以便更容易理解我的代码:
(1)对于每一天,如果我当天必须卖掉我的股票,那么我买入它的最低金额是多少?基本上,我在那天之前跟踪最低价格
(2)对于每一天,如果我当天要卖掉,我赚多少钱? (当天股票价格 - 最低价格)
这表明我必须跟踪两件事:(1)迄今为止的最低股价(2)迄今为止的最佳收益。
问题在于选择销售的那一天。我会在那个能给我最好收入的那天卖掉。这是我的Java代码:
public static void findBestDeal(double [] stocks) {
double minsofar = stocks[0];
double bestsofar = 0.0;
for(int i=1; i< stocks.length; i++) {
// What is the cheapest price to buy it if I'm going to sell it today
if(stocks[i-1] < minsofar) {
minsofar = stocks[i-1];
}
// How much do I earn if I sell it on ith day?
double current_deal = stocks[i] - minsofar;
// Is selling today better?
if(current_deal > bestsofar) {
bestsofar = current_deal;
}
}
System.out.println("Found the best deal: " + bestsofar + " (Bought at " + minsofar + " and sold at " + (minsofar+bestsofar) + ")");
}
答案 23 :(得分:0)
我必须指出一个面试问题,期待你解决它,因为O(n)是荒谬的。面试问题旨在证明您可以解决问题,您可以解决问题。你在O(N ^ 2)和O(N)中解决它的事实应该是无关紧要的。如果一家公司因为没有在O(N)中解决这个问题而过度雇佣你,而这可能不是你想要工作的公司。