it-swarm.com.ru

Получите самое большое хронологическое падение, минимальное и максимальное из массива с O(n)

Я написал функцию javascript для анализа самого большого падения в массиве. Но одна маленькая проблема все еще там. Как максимальное значение, я всегда получаю максимальное значение из моего массива отверстий, а не из моего падения.

Пример: Array: [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

7
Pommesloch

Ваш цикл должен отслеживать текущее падение и сравнивать его с предыдущим наибольшим падением. Вы можете сделать это, отслеживая индексы:

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
Ted Hopp

Вам нужно выполнить итерацию массива один раз (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
Salman A

Похоже, вы хотите, чтобы возвращаемые значения max и min были такими же, которые использовались при расчете наибольшего падения, а не общего значения max и min. В этом случае просто добавьте дополнительную переменную, чтобы сохранить их при обновлении 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

затем верните дополнительные сохраненные значения max и min.

2
גלעד ברקן

Вы должны отслеживать две вещи:

  • Максимальное значение, которое у вас есть до элемента 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]))

0
kakamg0

Чтобы добавить еще один к смеси .. Возможный подход состоит в том, чтобы сначала создать все диапазоны сбрасывания, чем получить тот, у которого наибольшее падение

Версия с уменьшением:

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

0
Me.Name