web-dev-qa-db-fra.com

Obtenez la plus grande chute chronologique, min et max d'un tableau avec O(n)

J'ai écrit une fonction javascript pour analyser la plus grosse baisse d'un tableau. Mais un petit problème est toujours là. En tant que valeur maximale, j'obtiens toujours la valeur maximale de ma matrice de trous et non de ma chute.

Exemple: Tableau: [100,90,80,120]

La plus grande chute serait entre 100 et 80. Donc max doit être 100 et minimum 80. Ma fonction renvoie toujours la valeur la plus élevée de tout le tableau. dans mon cas 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]
}

Je veux obtenir le plus grand delta chronologique correct de gauche à droite  Demo Image

7
Pommesloch

Votre boucle doit garder une trace de la chute actuelle et la comparer à la plus grosse chute précédente. Vous pouvez le faire en suivant les index:

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

Vous pouvez également le faire en conservant simplement les valeurs de début et de fin pour les dépôts actuels et les meilleurs, mais ma préférence serait de suivre explicitement les index. Cela me semble plus clair (plus facile à déboguer et à maintenir) de cette façon.

6
Ted Hopp

Vous devez itérer le tableau une fois (O(n)) et conserver un nombre permanent de valeurs min et max et:

  1. Réinitialisez-le à chaque fois que la valeur augmente. valeur précédente
  2. Mais notez-les si la différence est supérieure aux valeurs précédemment notées

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

Il semblerait que vous souhaitiez que les valeurs max et min renvoyées soient les mêmes que celles utilisées pour calculer la plus grande chute au lieu des valeurs max et min globales. Dans ce cas, ajoutez simplement une variable supplémentaire pour stocker celles-ci lorsque drop est mis à jour. Remplacer

drop = Math.max(tempDrop, drop)

avec une instruction if (pseudocode):

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

puis renvoyez les max et min supplémentaires stockés.

2
גלעד ברקן

Vous devez suivre deux choses:

  • La valeur maximale que vous avez pour un élément i.
  • La valeur minimale que vous avez d'un élément i à la fin de la liste.

Ensuite, il vous suffit de trouver la liste déroulante pour chaque index et de sélectionner celui qui est le plus grand.

Voici le code:

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

Pour ajouter une personne de plus au mélange ... Une approche possible consiste à créer d’abord toutes les plages de largage, puis à choisir celle qui présente la plus grande chute

Une version avec réduction:

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