javascript - 返回最大累计利润

Posted

技术标签:

【中文标题】javascript - 返回最大累计利润【英文标题】:javascript - return the maximum accumulated profit 【发布时间】:2018-12-02 20:09:46 【问题描述】:

我正在做一个我无法解决的练习。我需要通过买卖比特币来获得最大的累积利润。我有一个函数(A,Y),它在一段时间内接收一个 A = 不同价格的数组,一个 Y = 费用 限制:

注意:如果比特币以 0 买入并以 1 卖出,我们将损失 A[1] - A[0] =7050 -7200 - Y = -200。所以,这个动作没有做出来。

注意2:您当时只能拥有1个比特币。要出售,您必须先购买。要购买,您需要什么都没有或之前出售过。

注意3:运动必须是时间的结果。你不能在 A[5] 买入并在 A[4] 卖出

注4:如果不能盈利,则返回0

复杂度为 O(N)

A = [7200,7050,7300,7500,7440,7200,7300,7280,7400] //expected result 550
Y = 50
A[3] - A[1] - Y = 7500 - 7050 - 50 = 400
A[8] - A[5] - Y = 7400 - 7200 - 50 = 150
result = 550 //maximum accumulated profit

这就是我所拥有的

function solution(A, Y) 

 if(A.length < 2) 
     return 0;
 

 var minIndex = (A[0] > A[1]) ? 1 : 0;
 var minPrice = A[minIndex];

 var acum = 0;
 var i = minIndex + 1

 for (i; i< A.length-1; i++) 
    if( (A[i] - minPrice - Y) > (A[i+1] - minPrice - Y  )) 
        acum += A[i] - minPrice - Y;
        i = i+1
     else 
        acum += A[i + 1] - minPrice - Y;
        i = i+2
            
    minPrice = (A[i] > A[i+1]) ? A[i+1] : A[i];        
       
  return acum > 0 ? acum : 0;

实际上我得到了 450 但应该是 550

【问题讨论】:

有一个错误:如果 i 可能变成 A.length-1,那么 A[i+1] 将是 A[A.length]。好吧,这在 javascript 中应该是未定义的。 你怎么知道局部最大值? @NinaScholz 练习告诉我我应该得到的价值。 我认为正确的答案是 Mark_M 的答案。 【参考方案1】:

它看起来更复杂,因为您需要检查每一个购买价格和所有可能的销售价格。

结果是一棵采用这种蛮力方法的树。

此解决方案仅返回所有买入/卖出价格的最大利润。

function maxima(array, fee) 

    function iter(prices, index, count) 
        var i = 0, profit = 0;
        if (index >= array.length) 
            if (!prices.length || prices.length % 2) 
                return;
            
            if (prices.some((v, i, a) => i && (i % 2 ? a[i - 1] >= v : a[i - 1] < v))) 
                return;
            
            while (i < prices.length) 
                profit += prices[i + 1] - prices[i] - fee;
                i += 2;
            
            if (!result.length || result[0].profit < profit) 
                result = [ profit, prices ];
             else if (result[0].profit === profit) 
                result.push( profit, prices );
            
            return;
        
        iter(prices.concat(array[index]), index + 1); // buy/sell
        iter(prices, index + 1);                      // no action
    

    var result = [];
    iter([], 0, 0);
    return result;


console.log(maxima([7200, 7050, 7300, 7500, 7440, 7200, 7300, 7280, 7400], 50));
.as-console-wrapper  max-height: 100% !important; top: 0; 

【讨论】:

很好的解决方案,确实比我想象的要复杂 @גלעדברקן,我可以插入一些短路。 @Mark_M,已经很晚了,我考虑了一下,也许明天我会提出一个更短的方法。【参考方案2】:

我知道你已经有了答案,但我想提出一个可能的 O(n) 解决方案。这个想法是您监控价格走势的方向以及本地最小值和最大值。只要价格从本地最小值或最大值改变方向超过 Y,您就可以定义方向变化。您根据方向变化进行买卖。

var A = [6000, 7200, 7050, 7040, 7045, 7041, 7039, 7300, 7500, 7490, 7480, 7501, 7440, 7200, 7300, 7280, 7400];
var A = [7200, 7050, 7300, 7500, 7440, 7200, 7300, 7280, 7400];
let Y = 50

function buysell(A, Y) 
  let direction = -1
  let min = A[0]
  let max = 0
  let total = 0

  for (let i = 1; i < A.length; i++) 
    if (direction == -1) 
      if (A[i] < min) min = A[i]
      if (A[i] - min > Y)  // only change direction if change is greater than Y
        direction = 1;
        max = A[i]
        console.log('buy at', min)
      
     else  // price is going up      
      if (A[i] > max) max = A[i]
      if (max - A[i] > Y) 
        total += max - min - Y
        console.log('sell at ', max)
        min = A[i]
        direction = -1
      
    
  
  // buy at end if price was going up
  if (direction == 1) 
    console.log('sell at ', max)
    total += max - min - Y
  
  return total

console.log("total: ", buysell(A, Y))

// Test with some edge cases:
var A = [6000, 7200,7050, 7040, 7045, 7041, 7039,7040, 7300,7500, 7490, 7480,7501, 7440,7200,7300,7280,7400];
console.log("total: ", buysell(A, Y))

var A = [ 7172, 2477, 4755, 2297, 2893, 8863 ]
console.log("total: ", buysell(A, Y))

【讨论】:

对于[ 7172, 2477, 4755, 2297, 2893, 8863 ], 50 似乎失败了我得到buy at 2477, sell at 8863 =&gt; 6336,当我相信答案是8863 - 50 - 2297 + 4755 - 50 - 2477 = 8744 谢谢@גלעדברקן - 我想我在方向改变时设置了新的本地最大值错误。我认为编辑修复了它。【参考方案3】:

(我相信 Mark_M 的答案在这里是最好的,但为了完整起见,我会留下我的答案。)

对于每个销售价格,我们都想知道它之前的最佳购买价格,以便我们可以将该销售与之前累积的最高价格配对。我们可以有一个O(n^2) 算法,因为无论如何我们都必须往回遍历。

function f(A, Y)
  let m = [0].concat(new Array(A.length - 1));

  for (let i=1; i<A.length; i++)
    let smallest = A[i-1];
    m[i] = m[i - 1];

    for (let j=i-1; j>0; j--)
      smallest = Math.min(smallest, A[j]);

      if (smallest < A[i] + Y)
        m[i] = Math.max(m[i], A[i] - smallest - Y + (m[j - 1] || 0));
    
  

  return m[m.length - 1];


var a = [7200,7050,7300,7500,7440,7200,7300,7280,7400];

console.log(f(a, 50));

【讨论】:

以上是关于javascript - 返回最大累计利润的主要内容,如果未能解决你的问题,请参考以下文章

华为OD机试真题 JavaScript 实现最大利润2023 Q1 | 100分

华为OD机试真题 JavaScript 实现最大利润2023 Q1 | 100分

javascript 最大利润

华为机试真题 C++ 实现最大利润2022.11 Q4 新题

经典算法四:股票的最大利润(动态规划)

Mysql数据累加,实现cumsum(累加)的功能