【问题标题】:Maximum profit that can be obtained - Buying and Selling可以获得的最大利润 - 买卖
【发布时间】:2017-01-03 20:06:25
【问题描述】:

假设我们准确预测了梅西在N 天期间的价格。预测以列表形式给出,其中p_i 代表玩家在i 当天的价格。 Bob 计划在此期间进行多次连续交易,但一次只能拥有一个梅西,因此需要在再次购买之前卖掉他。

鲍勃一开始预算有限B,他买不起梅西,因为他买不起。当然,Bob 可以将他从买卖他的 Messis 中获得的任何利润添加到他的预算中。对他来说幸运的是,有些时候他会从事先打开一个随机的礼品包开始。

最后鲍勃只是想尽可能多地获得利润,然后卖掉他最后的梅西。


输入格式:

在输入文件的第一行,你会找到 3 个整数,N、B 和 M。

N 表示 Bob 预测梅西价格的天数。 B 代表 Bob 的初始预算。 M 可以是 0 或 1;如果 Bob 开始时没有要出售的初始梅西,则为 0;如果他确实开始时需要出售的初始梅西,则为 1。

在下一行你会找到 N 个整数:p1, p2, ... , pN,用空格隔开,其中 pi 代表梅西在第 i 天的价格。


给定测试用例

测试 1

7 5 0

20 10 30 5 10 10 20

正确答案:15

解释:Bob 以 5 的初始预算开始,并且没有要出售的初始梅西。在他的价格降到5之前他不能买任何梅西,所以他的利润只有(20-5) = 15


测试 2

7 0 1

20 10 50 80 60 20 10

正确答案:90

说明: Bob 以 0 的初始预算和一个要出售的梅西开始。因此他以20的价格卖掉他最初的梅西,以10的价格买回他并以80的价格卖掉他,因此他的利润是20 + (80-10) = 90


这个问题是在一次采访中给我的,我无法提出一个有效的解决方案。与此同时,我在这个问题上发现了一些更简单的变体,例如 Maximum profit by buying and selling a share at most twice ,但我未能成功理解如何使这种想法适应我​​的问题。

到目前为止,我只能想出一个蛮力解决方案,它远远超出了我给定的时间限制(C++ 为 0.1 秒,其中 1

我正在寻找解决方案和思考这类问题的方法,我似乎找不到正确的方法来思考这个问题。

【问题讨论】:

  • 请解释我的问题是如何跑题的。查看“帮助”部分后,我发现合适的问题可能涉及:特定的编程问题,或软件算法,或程序员常用的软件工具;并且是软件开发独有的实用、可回答的问题
  • 一个非常宽泛、没有任何代码的一般问题通常被认为是本网站的题外话,这更多是为了解决代码的特定问题。 softwareengineering.stackexchange.com 可能更适合这个问题。
  • 这个问题有多宽泛?这是一个非常具体的问题,具有非常具体的要求。如“主题”部分所述,该问题不需要附加任何代码,只要它基于上述列表中的概念即可。 " 我们认为最好的(不是绝对必要的)Stack Overflow 问题中有一些源代码,但如果您的问题通常涵盖...[以上列表]...**那么您就在提问的好地方!**"
  • 对不起,我不太关注。你能把它分解成 1/8 盎司、1/4 盎司、1 盎司等,或者甚至是克。那会很好。
  • 投票关闭的用户给出了以下具体原因:“寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需的行为、特定的问题或错误以及最短的在问题本身中重现它所必需的代码。没有明确问题陈述的问题对其他读者没有用。请参阅:如何创建最小、完整和可验证的示例。我也不跟。这与我的问题有什么关系?如果你不能解决一个不会使陈述不正确的问题,那只是意味着你不能解决这个问题。

标签: algorithm dynamic-programming


【解决方案1】:

我们可以使用动态规划。

  1. 让我们将f0(i) 定义为如果我们在一天开始时没有梅西i 时我们可以获得的最大预算。 让f1(i) 具有相同的值,以防我们找到他。

  2. i = 0 的基值取决于我们是否在一开始就有他。

  3. 过渡如下:

    • 我们可以从i 转到i + 1,什么都不做

    • 如果我们有梅西,我们可以卖掉他(设置f0(i + 1) = max(f0(i + 1), f1(i) + price(i))

    • 如果我们没有他,而且我们的预算足够大,我们可以买他 (做f1(i + 1) = max(f1(i + 1), f0(i) - price(i))

  4. 答案是f0(n)(这意味着所有日子都过去了,我们没有他)。

这个解决方案显然需要线性的时间和空间,所以任何 合理的 C++ 实现应该符合您的要求。

【讨论】:

  • 非常感谢您这么快发布解决方案!但我还不完全理解你的方法。首先,您如何实际设置 f0(0) 和 f1(0) 的初始值?例如,如果我们没有梅西 f0(0) = initial_budget 因为我们不能出售,所以我们只有初始预算,但是 f1(0) 呢?
  • @user43389 如果我们有他,f0(0) = -infinityf1(0) = B。否则,f0(0) = Bf1(0) = -infinity
  • 对我来说仍然没有意义的另一件事...以 f0(1) 为例,它在循环之前尚未计算,但我们尝试将其设置为 max(f0( 1), f1(0) + price(0)),结果不总是f1(0) + price(0)吗?
  • 另外,在迭代时,你给了 3 个分支,要么我们有或没有梅西,要么我们跳过.. 但我们总是在前两个中,所以你什么时候真正做什么都没有?
  • @user43389 是的,我们总是可以跳过。
【解决方案2】:

问题的第一个简化就是将梅西最初的“礼物”转换成梅西初始价格等量的金钱。用户一开始可以选择买回梅西还是不买回来。

之后,您会找到第一个足以让用户购买梅西的价格,并丢弃之前的所有预测。然后,找到预测价格的所有 local 最小值和 local 最大值,并在所有最小值上买入并在所有最大值上卖出,但记住不要回购,如果局部最小值是最后的预测。

这应该可以解决 O(N) 中的问题。

编辑:可以通过序列的 2 阶差找到局部最小值或最大值:

d[i] = p[i+1] - p[i]
d2[i] = d[i] - d[i-1]

如果d2[i] > 0,那么它是本地最小值;如果d2[i] < 0,那么它是局部最大值。显然,您需要注意一些边界条件,但应该不会太难。

【讨论】:

    【解决方案3】:
    // input
    long predictionLength;
    long budget;
    bool startWithMessi;
    long prediction[MAX_PREDICTION_LENGTH];
    
    // output
    long profit;
    
    ifstream fin;
    fin.open( DATA_FILE_NAME );
    fin >> predictionLength >> budget >> startWithMessi;
    for( long day = 0; day < predictionLength; day++ )
      fin >> prediction[day];
    fin.close();
    
    long money = budget;
    bool messi = startWithMessi;
    long dayIndex = 0;
    while( dayIndex < predictionLength )
    {
      if( messi )
      {
        if( dayIndex == predictionLength - 1
          || prediction[dayIndex] > prediction[dayIndex + 1] )
        {
          money += prediction[dayIndex];
          messi = false;
        }
      }
      else
        if( dayIndex < predictionLength - 1
          && prediction[dayIndex] < prediction[dayIndex + 1]
          && money >= prediction[dayIndex] )
        {
          money -= prediction[dayIndex];
          messi = true;
        }
      dayIndex++;
    }
    
    profit = money - budget;
    
    cout << profit << endl;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-06
      • 2015-07-21
      • 1970-01-01
      • 1970-01-01
      • 2019-12-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多