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

时间:2018-11-26 12:36:52

标签: javascript arrays algorithm calculation

我已经编写了一个javascript函数来分析数组中最大的下降。但是仍然存在一个小问题。作为最大值,我总是从孔阵列而不是从液滴获得最大值。

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

最大降幅将在100到80之间。因此max必须为100,min必须为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]
}

我想按时间顺序从左到右获得最大的增量 Demo Image

6 个答案:

答案 0 :(得分:6)

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

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]))

您也可以通过仅保留当前和最佳放置的开始和结束值来做到这一点,但我的首选是明确地跟踪索引。这样对我来说似乎更清晰(更易于调试和维护)。

答案 1 :(得分:2)

您需要迭代一次数组(O(n)),并保持最小和最大值的连续计数,以及:

  1. 每次值增加w.r.t时将其重置。以前的值
  2. 但是如果差异大于先前记录的值,请注意它们

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]));

答案 2 :(得分:2)

听起来您希望返回的最大和最小与用于计算最大下降的相同,而不是总的最大和最小。在这种情况下,只需添加一个附加变量来存储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

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

答案 3 :(得分:0)

您需要跟踪两件事:

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

然后,您只需要找到每个索引的跌幅并选择最大的一个。

代码如下:

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]))

答案 4 :(得分:0)

要再添加一个。 一种可能的方法是先创建所有放置-放置范围,而不是放置最大放置的范围

带有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]));

答案 5 :(得分:-1)

这完全按照预期的方式工作(根据您的预期输出),如下面的代码片段所示。

问题必须出在如何将数据作为数组发送。

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

但是,如果您要查找的是“最大值”,“最小值”,然后是最大的差异,即最大值和最小值之间的差异(在给定的示例中为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。