面试问题:最大多次销售利润

时间:2011-09-14 17:24:19

标签: algorithm

我对我在面试中得到的算法问题有疑问,我似乎无法弄明白。我理解它应该如何工作,但无法通过算法进行排序。

因此假设一家公司交易油桶,并且一次只能保留一个油桶。假设公司知道一年中每天的每桶价格。所以它作为一个数组传递。如何编写算法来查找何时买卖?

以下是简化仅5天的示例: 70 74 73 72 76,分别为星期一至星期五。

这里最好的办法是周二(74)周二买入(74),然后周四买入(72)并在周五卖出(76)。应该递归接近吗?我真的想解决这个问题。

谢谢,

6 个答案:

答案 0 :(得分:11)

我认为你想要最大化你的利润,对吗?

在这种情况下,您只需在当地最低价购买并以当地最高价出售,这将是一个简单的线性搜索。

实际上就是这么简单。证明:

让我们表示

p(i) ... the price of oil on day i
have(i) ... 1 if we retain the barrel overnight from day i to day i+1, 0 otherwise

has仅在[0,N-1]

中为i定义

现在,如果我们在k日购买并在l日出售,我们就有

have(k) = 1
have(l) = 0
have(i) = 1 for k < i < l

利润将是

p(l)-p(k) = sum over {i from k to l-1} (p(i+1)-p(i))

让我们表示

M(i) = max(p(i+1) - p(i), 0)

对于所有可能的布尔函数have,我们有

profit(have) = sum over {i where have(i)==1} (p(i+1) - p(i))
 <= sum over {i where have(i)==1} max(p(i+1) - p(i), 0)
 <= sum over {i where have(i)==1} M(i)
 <= sum over {i in [0, N-1]} M(i)

第二行来自max(x, 0) >= x,第三行是M(i)的简单重写,第四行来自M(i) >= 0

现在,如果我们设置have(i) == (p(i+1)>p(i)),它将获得与上面相同的利润,这意味着它是最大的。此外,这意味着您以当地最低价购买并以当地最高价出售。

答案 1 :(得分:2)

O(N)时间和O(1)空间

中的算法
Starting at index 0
If you haven't bought an oil barrel:
    if price[i] < price[i + 1], buy at price[i]
    // if price[i] >= price[i + 1], you will never buy at price[i]
    // as price[i + 1] can bring you more money. So just wait...
If you have bought an oil barrel:
    if price[i] > price[i + 1], sell at price[i]
    // if price[i] <= price[i + 1], you will never sell at price[i]
    // as price[i + 1] can bring you more money. So just wait...

C ++实现:

#include <iostream>
#include <vector>

int best_profit(const std::vector<int>& prices)
{
  bool buying = true;
  int buying_price = 0;
  int profit = 0;

  for(std::vector<int>::size_type i = 0; i < prices.size() - 1; ++i)
  {
    if(buying)
    {
      if(prices[i] < prices[i + 1])
      {
        buying_price = prices[i];
        buying = false;
      }
    }
    else if(prices[i] > prices[i + 1])
    {
      profit += prices[i] - buying_price;
      buying = true;
    }
  }

  if(!buying) // The last price is the highest one!
  {
    profit += prices[prices.size() - 1] - buying_price;
  }

  return profit;
}

int main()
{
  std::vector<int> prices1{1};
  std::vector<int> prices2{1, 2};
  std::vector<int> prices3{3, 2};
  std::vector<int> prices4{70, 74, 73, 72, 76};
  std::vector<int> prices5{70, 75, 71, 80, 96, 100, 15, 50, 60};

  std::cout << "prices1: " << best_profit(prices1) << std::endl;
  std::cout << "prices2: " << best_profit(prices2) << std::endl;
  std::cout << "prices3: " << best_profit(prices3) << std::endl;
  std::cout << "prices4: " << best_profit(prices4) << std::endl;
  std::cout << "prices5: " << best_profit(prices5) << std::endl;
}

输出:

prices1: 0
prices2: 1
prices3: 0
prices4: 8
prices5: 79

答案 2 :(得分:2)

以当地最高价出售,以当地最低价购买。在开始之前将价格视为无穷大,在结束之后将其视为零。

答案 3 :(得分:1)

以你的例子或桶价:[70,74,73,72,76]。

从给定的价格,我可以计算每日价格变化(即今天的价格 - 前一天的价格)。 &#34;价格变动阵列&#34;在这种情况下将是[4,-1,-1,4]。

在&#34;价格变动数组&#34;中,正数表示价格上涨,负数表示价格与前一天相比有所下降。

解决方案是从&#34;价格变化数组中找出所有连续的子阵列。它只包含正数。

使用这个想法,我写了下面的python代码来打印购买和相应的销售日:

barrel_price = [70, 74, 73, 72, 76]
trading_days = {} #dictionary for storing {buy_day: sell_day}
buy_day=0
sell_day=buy_day+1

while sell_day < len(barrel_price):
    if barrel_price[sell_day]-barrel_price[sell_day-1]>0:
        #don't sell if price is still increasing
        sell_day=sell_day+1
        trading_days[buy_day] = sell_day-1
    else:
        #don't buy if price is still decreasing
        buy_day=sell_day
        sell_day=buy_day+1

print trading_days

这打印&#34; {0: 1, 3: 4}&#34; 对于第一对0:1,即买入第0天和卖出第1天,在barrel_price数组中相应的价格是70和74。 对于下一对3:4,相应的购买价格为72,售价为76。

答案 4 :(得分:0)

L [j]表示截至第j天的利润 L [j] = L [j-1] + MAX(0,P j -P j-1
P j =第j天的股票价格 解决方案在于L [n],因为每个L [j]给出了直到该点所获得的最大利润,L [n]给出了最后一天获得的最大利润。
运行时间: O(n)

答案 5 :(得分:-1)

只是比较价格:

每周搜索最低价格

(loop1)

(if currentPrice < nextPrice) 
currentPrice = nextPrice

并获得currentPrice(date)和nextLowerSellPrice

之间的最高价格
(loop2)

(if currentHighPrice<nextHighPrice)
currentHighPrice = nextHighPrice
else
sell(currentHighPriceDay)