从具有 O(n) 的数组中获取最大的时间下降、最小值和最大值

Posted

技术标签:

【中文标题】从具有 O(n) 的数组中获取最大的时间下降、最小值和最大值【英文标题】:Get the biggest chronological drop, min and max from an array with O(n) 【发布时间】:2019-04-28 02:34:24 【问题描述】:

我编写了一个 javascript 函数来分析数组中的最大下降。但是还有一个小问题。作为最大值,我总是从我的洞数组而不是从我的 drop 中获取最大值。

示例: 数组:[100,90,80,120]

最大的下降将在 100 到 80 之间。因此最大值必须为 100,最小值为 80。我的函数总是返回整个数组中的最大值。在我的情况下 120

function checkData(data) 
  let max = 0
  let min = 0
  let drop = 0

  for (let i = 0; i < data.length; i++) 
      if (max < data[i]) 
          max = data[i] //?
       else 
          let tempDrop = max - data[i]
          drop = Math.max(tempDrop, drop)
          min = max - drop
      
  
  return [max, min, drop]

我想从左到右获得时间顺序正确的最大增量

【问题讨论】:

当你说drop时,你的意思是不同吗? @cmprogram,我的意思是最大值和最小值之间的最大差值。 这个数组排序了吗?你说drop是什么意思? return [max, min, drop] 什么是最大、最小和下降? [100,110,120,70,60,50,90,300,200] 的 drop 输出是多少? 【参考方案1】:

这完全符合预期(根据您的预期输出),如以下代码 sn-p 所示。

问题一定在于您如何将数据作为数组发送。

alert(checkData([100, 90, 80, 120]));

function checkData(data) 
  let max = 0
  let min = 0
  let drop = 0

  for (let i = 0; i < data.length; i++) 
    if (max < data[i]) 
      max = data[i] //?
     else 
      let tempDrop = max - data[i]
      drop = Math.max(tempDrop)
      min = max - drop
    
  
  return [max, min, drop]
// Output : 120, 80, 20

但是,如果您要查找的是 Max、Min,然后是最大的差异,即 max 和 min 之间的差异,在您给定的示例中为 40,那么您可以简单地执行此操作。

alert(checkData([100, 90, 80, 120]));

function checkData(data) 

  let max = data.reduce(function(a, b) 
    return Math.max(a, b);
  );
  let min = data.reduce(function(a, b) 
    return Math.min(a, b);
  );

  let drop = max-min;

  return [max, min, drop];
  
// Output : 120, 80, 40

我只提到这一点,因为我不知道你为什么说你期望最大的差异是 20,给定 100 和 80,当你在同一个数组中有 120 和 80 时,意味着最大的差异是 40。

【讨论】:

谢谢,但正确的回报必须是 max = 100,min = 80 和 drop = 20。看看我添加到我的帖子中的图形 但是 100 不是最大值...如果您不想包含 120,请不要将其包含在数组中... 此数据来自共享 API。这就是为什么我需要这个按时间顺序从左到右的增量。股价从 100 跌至 80。这是 -20% 的跌幅。在我的尝试中,我错过了时间方面 OP 想要与最大下降相关联的最大值和最小值,其中下降是一系列下降的数据值。降幅最大的是从 100 到 80(索引 0 到 2)。【参考方案2】:

您需要跟踪两件事:

您拥有的最大值为元素i。 从元素 i 到列表末尾的最小值。

然后你只需要找到每个索引的 drop 并选择哪个最大。

代码如下:

function maxDrop (data) 
  if (!data || data.length === 0) 
    return;
  
  const max = [];
  const min = [];
  for (let i = 0; i < data.length; i++) 
    const left = data.slice(0, i);
    const right = data.slice(i, data.length);
    max.push(Math.max.apply(null, left));
    min.push(Math.min.apply(null, right));
  
  let maxDrop = max[0] - min[0];
  let maxValue = max[0];
  let minValue = min[0];
  for (let j = 0; j < data.length; j++) 
    const drop = max[j] - min[j];
    if (maxDrop < drop) 
      maxDrop = drop;
      maxValue = max[j];
      minValue = min[j];
    
  
  return [maxValue, minValue, maxDrop];


console.log(maxDrop([100,90,80,120]))
console.log(maxDrop([100,110,120,300,200,70,60,50,90,400]))
console.log(maxDrop([100,90,80,120,30]))

【讨论】:

[100, 90, 80, 120, 30] 失败。输出是[100, 80, 20],但应该是[120, 30, 90] @TedHopp 已修复,我在搜索最小值时排除了最后一个元素。谢谢!【参考方案3】:

您需要对数组进行一次迭代 (O(n)) 并保持最小值和最大值的运行计数,并且:

    每次值增加 w.r.t 时重置它。以前的值 但如果差异大于之前记录的值,请记下它们

function checkData(array) 
  var currentmax = array[0];
  var currentmin = array[0];
  var overallmax = array[0];
  var overallmin = array[0];
  var i;
  for (i = 1; i < array.length; i++) 
    if (array[i] <= array[i - 1]) 
      // value is same or decreased
      currentmin = array[i];
     else 
      // check if previous iteration was the largest
      if (currentmax - currentmin > overallmax - overallmin) 
        overallmax = currentmax;
        overallmin = currentmin;
      
      // restart
      currentmax = array[i];
      currentmin = array[i];
    
  
  // check if last iteration was the largest
  if (currentmax - currentmin > overallmax - overallmin) 
    overallmax = currentmax;
    overallmin = currentmin;
  

  return [overallmax, overallmin, overallmax - overallmin];

console.log(checkData([100, 90, 80, 120]));
console.log(checkData([100, 90, 80, 120, 200, 100, 90]));
console.log(checkData([10, 100, 50, 50, 10, 100, 50, 50, 1]));

【讨论】:

这对于 [100, 90, 80, 120, 200, 100 ,90] 失败。返回必须是 max = 200,min = 90 和 drop = 110 逻辑是合理的(我认为),我只需要在每次值更改时更新最大最小值。请参阅修改后的答案。【参考方案4】:

听起来您希望返回的最大值和最小值与用于计算最大下降而不是总体最大值和最小值的值相同。在这种情况下,只需添加一个额外的变量来存储更新 drop 时的变量。替换

drop = Math.max(tempDrop, drop)

使用 if 语句(伪代码):

if current_drop is greater than stored_drop:
  stored_drop = current_drop
  stored_max_min = current max and min

然后返回额外存储的最大值和最小值。

【讨论】:

【参考方案5】:

您的循环应该跟踪当前的下降并将其与之前的最大下降进行比较。您可以通过跟踪索引来做到这一点:

function checkData(data) 
  let bestDropStart = 0
  let bestDropEnd = 0
  let bestDrop = 0
  let currentDropStart = 0
  let currentDropEnd = 0
  let currentDrop = 0
  for (let i = 1; i < data.length; i++) 
    if (data[i] < data[i - 1]) 
      // we are dropping
      currentDropEnd = i
      currentDrop = data[currentDropStart] - data[i]
     else 
      // the current drop ended; check if it's better
      if (currentDrop > bestDrop) 
        bestDrop = currentDrop
        bestDropStart = currentDropStart
        bestDropEnd = currentDropEnd
      
      // start a new drop
      currentDropStart = currentDropEnd = i
      currentDrop = 0
    
  
  // check for a best drop at end of data
  if (currentDrop > bestDrop) 
    bestDrop = currentDrop
    bestDropStart = currentDropStart
    bestDropEnd = currentDropEnd
  
  // return the best drop data
  return [data[bestDropStart], data[bestDropEnd], bestDrop]


console.log(checkData([100, 90, 80, 120]))
console.log(checkData([100, 90, 80, 120, 30]))
console.log(checkData([70, 100, 90, 80]))
console.log(checkData([100, 90, 80, 120, 30, 50]))

您也可以只保留当前和最佳下降的开始值和结束值,但我更喜欢显式跟踪索引。这样对我来说似乎更清晰(更容易调试和维护)。

【讨论】:

【参考方案6】:

再添加一个.. 一种可能的方法是首先创建所有的下降范围,而不是获得最大下降的范围

带有reduce的版本:

function checkData(data) 
let dropInd = 1,
  	mx = data.reduce((arr,val, ind) => 
 if(ind && val > data[ind-1])dropInd++;  	      
 arr[dropInd] = arr[dropInd] || max:val;
 arr[dropInd].min = val;
 arr[dropInd].drop = arr[dropInd].max - val;
 return arr;
, []) //after reduce, islands are created based on 'dropInd'  
  .sort((v1,v2)=>v2.drop - v1.drop) //sort by drop descending
  [0]; //the first value now contains the maximum drop  

  return [mx.max,mx.min,mx.drop];




console.log(checkData([100, 90, 80, 120]));
console.log(checkData([100, 90, 80, 120, 200, 100 ,90]));
console.log(checkData([200,100, 90, 80, 120,  100 ,90]));
console.log(checkData([200,120,190, 90, 80, 120,  100 ,90]));

【讨论】:

以上是关于从具有 O(n) 的数组中获取最大的时间下降、最小值和最大值的主要内容,如果未能解决你的问题,请参考以下文章

从队列中获取 O(1) 时间内的最小值/最大值? [关闭]

使用 NumPy 从矩阵中获取最小/最大 n 值和索引的有效方法

PHP:将一个数字分隔为具有最小值和最大值的 10er 数组

O(n log n)求最长上升子序列与最长不下降子序列

算法——O(n)解决无序数组排序后的相邻最大差值

Java 实例 – 数组获取最大和最小值