web-dev-qa-db-fra.com

Comment trouver le plus petit commun multiple d'une plage de nombres?

Étant donné un tableau de deux nombres, laissez-les définir le début et la fin d'une plage de nombres. Par exemple, [2,6] signifie la plage 2,3,4,5,6. Je veux écrire du code javascript pour trouver le plus petit commun multiple de la gamme. Mon code ci-dessous ne fonctionne que pour les petites plages, pas quelque chose comme [1,13] (qui est la plage 1,2,3,4,5,6,7,8,9,10,11,12,13), ce qui provoque un débordement de pile. . Comment trouver efficacement le plus petit multiple commun d'une plage?

function leastCommonMultiple(arr) {
    var minn, max;
    if ( arr[0] > arr[1] ) {
        minn = arr[1];
        max = arr[0];
    } else {
        minn = arr[0];
        max = arr[1];
    }
    function repeatRecurse(min, max, scm) {
        if ( scm % min === 0 && min < max ) {
            return repeatRecurse(min+1, max, scm);
        } else if ( scm % min !== 0 && min < max ) {
            return repeatRecurse(minn, max, scm+max);
        }
        return scm;
    } 
    return repeatRecurse(minn, max, max);
}
14
john chau

Je pense que cela fait le travail.

function leastCommonMultiple(min, max) {
    function range(min, max) {
        var arr = [];
        for (var i = min; i <= max; i++) {
            arr.Push(i);
        }
        return arr;
    }

    function gcd(a, b) {
        return !b ? a : gcd(b, a % b);
    }

    function lcm(a, b) {
        return (a * b) / gcd(a, b);   
    }

    var multiple = min;
    range(min, max).forEach(function(n) {
        multiple = lcm(multiple, n);
    });

    return multiple;
}

leastCommonMultiple(1, 13); // => 360360
34
rgbchris
function smallestCommons(arr) {
  var max = Math.max(...arr);
  var min = Math.min(...arr);
  var candidate = max;

  var smallestCommon = function(low, high) {
    // inner function to use 'high' variable
    function scm(l, h) {
      if (h % l === 0) {
        return h;
      } else {
        return scm(l, h + high);
      }
    }
    return scm(low, high);
  };

  for (var i = min; i <= max; i += 1) {
    candidate = smallestCommon(i, candidate);
  }

  return candidate;
}

smallestCommons([5, 1]); // should return 60
smallestCommons([1, 13]); // should return 360360
smallestCommons([23, 18]); //should return 6056820
4
Brian

Le mien n’est pas aussi sophistiqué que les autres réponses mais je pense que c’est facile à lire. 

function smallestCommons(arr) {
	//order our array so we know which number is smallest and which is largest
	var sortedArr = arr.sort(),
	//the smallest common multiple that leaves no remainder when divided by all the numbers in the rang
	smallestCommon = 0,
	//smallest multiple will always be the largest number * 1;
	multiple = sortedArr[1];

	while(smallestCommon === 0) {
		//check all numbers in our range
		for(var i = sortedArr[0]; i <= sortedArr[1]; i++ ){
			if(multiple % i !== 0 ){
				//if we find even one value between our set that is not perfectly divisible, we can skip to the next multiple
				break;
			}

			//if we make it all the way to the last value (sortedArr[1]) then we know that this multiple was perfectly divisible into all values in the range
			if(i == sortedArr[1]){
				smallestCommon = multiple;
			}

		}

		//move to the next multiple, we can just add the highest number.
		multiple += sortedArr[1];
	}

	console.log(smallestCommon);
	return smallestCommon;
}


smallestCommons([1, 5]); // should return 60.
smallestCommons([5, 1]); // should return 60.
smallestCommons([1, 13]); // should return 360360.
smallestCommons([23, 18]); // should return 6056820.

Edit: transformé la réponse en extrait.

2
Bullyen

Hey je suis tombé sur cette page et je voulais partager ma solution :)

function smallestCommons(arr) {
  var max = Math.max(arr[0], arr[1]),
      min = Math.min(arr[0], arr[1]),
      i = 1;
  while (true) {
    var count = 0;
    for (j = min; j < max; j++) {
      if (max * i % j !== 0) {
        break;
      }
      count++;
    }
    if (count === (max - min)) {
      alert(max * i);
      return max * i;
    }
    i++;
  }
}
smallestCommons([23, 18]);

1
user1137342

Ceci est une version non récursive de votre approche originale.

function smallestCommons(arr) {
  // Sort the array
  arr = arr.sort(function (a, b) {return a - b}); // numeric comparison;
  var min = arr[0];
  var max = arr[1];

  var numbers = [];
  var count = 0;

  //Here Push the range of values into an array
  for (var i = min; i <= max; i++) {
    numbers.Push(i);
  }
  //Here freeze a multiple candidate starting from the biggest array value - call it j
  for (var j = max; j <= 1000000; j+=max) {

    //I increase the denominator from min to max
    for (var k = arr[0]; k <= arr[1]; k++) {

      if (j % k === 0) { // every time the modulus is 0 increase a counting 
        count++; // variable
      }
    }

    //If the counting variable equals the lenght of the range, this candidate is the least common value
    if (count === numbers.length) { 
      return j; 
    }
    else{
      count = 0; // set count to 0 in order to test another candidate
    }
  }
}

alert(smallestCommons([1, 5]));

1
Giorgio Giuliani

Fonction LCM pour une plage [a, b]

// Euclid algorithm for Greates Common Divisor
function gcd(a, b)
{ 
	return !b ? a : gcd(b, a % b);
} 

// Least Common Multiple function
function lcm(a, b) 
{
	return a * (b / gcd(a,b));
}

// LCM of all numbers in the range of arr=[a, b] 
function range_lcm(arr)
{
	// Swap [big, small] to [small, big]
	if(arr[0] > arr[1]) (arr = [arr[1], arr[0]]);

	for(x = result = arr[0]; x <= arr[1]; x++) {
		result = lcm(x, result);
	}
	
	return result; 
}

alert(range_lcm([8, 5])); // Returns 840

1
krmld
function lcm(arr) {
  var max = Math.max(arr[0],arr[1]),
      min = Math.min(arr[0],arr[1]),
      lcm = max;
  var calcLcm = function(a,b){
    var mult=1;
    for(var j=1; j<=a; j++){
      mult=b*j;
      if(mult%a === 0){
        return mult;
      }
    }
  };
  for(var i=max-1;i>=min;i--){
    lcm=calcLcm(i,lcm);
  }
  return lcm;
}
lcm([1,13]); //should return 360360.
0
Shivam

c'est un autre moyen très simple et peu complexe.

function smallestCommons(arr) {
  let smallestNum = arr[0] < arr[1] ? arr[0] : arr[1];
  let greatestNum = arr[0] > arr[1] ? arr[0] : arr[1];
  let initalsArr = [];
  for(let i = smallestNum; i <= greatestNum; i++){
    initalsArr.Push(i);
  }
  let notFoundFlag = true;
  let gNMltpl = 0;
  let filteredArrLen; 
  while(notFoundFlag){
    gNMltpl += greatestNum;
    filteredArrLen = initalsArr.filter((num)=>{
      return (gNMltpl / num) === Math.floor((gNMltpl / num)) 
    }).length;
    if(initalsArr.length == filteredArrLen){
      notFoundFlag = false;
    }
  }
  return gNMltpl;
}
0
Khalifa Gad
 function leastCommonMultiple(arr) {
    /*
      function range(min, max) {
        var arr = [];
       for (var i = min; i <= max; i++) {
        arr.Push(i);
      }
       return arr;
    }
    */
    var min, range;
     range = arr;
    if(arr[0] > arr[1]){
       min = arr[1];
    }
    else{
       min = arr[0]
    }

    function gcd(a, b) {
        return !b ? a : gcd(b, a % b);
    }

    function lcm(a, b) {
        return (a * b) / gcd(a, b);   
    }

   var multiple = min;
    range.forEach(function(n) {
       multiple = lcm(multiple, n);
    });

   return multiple;
}

console.log (lessCommonMultiple ([1, 13]))

0
john chau

Voici ma solution. J'espère que vous trouverez cela facile à suivre:

function smallestCommons(arr) {
  var min = Math.min(arr[0], arr[1]);
  var max = Math.max(arr[0], arr[1]);

  var smallestCommon = min * max;

  var doneCalc = 0;

  while (doneCalc === 0) {
    for (var i = min; i <= max; i++) {
      if (smallestCommon % i !== 0) {
        smallestCommon += max;
        doneCalc = 0;
        break;
      }
      else {
        doneCalc = 1;
      }
    }
  }

  return smallestCommon;
}
0
Yup.

Voici une autre solution non récursive pour la boucle

function smallestCommons(arr) {
  var biggestNum = arr[0];
  var smallestNum = arr[1];
  var thirdNum;
  //make sure biggestNum is always the largest
  if (biggestNum < smallestNum) {
    thirdNum = biggestNum;
    biggestNum = smallestNum;
    smallestNum = thirdNum;
  }
  var arrNum = [];
  var count = 0;
  var y = biggestNum;

  // making array with all the numbers fom smallest to biggest
  for (var i = smallestNum; i <= biggestNum; i += 1) {
    arrNum.Push(i);
  }

  for (var z = 0; z <= arrNum.length; z += 1) {
    //noprotect
    for (y; y < 10000000; y += 1) {
      if (y % arrNum[z] === 0) {
        count += 1;
        break;
      }
      else if (count === arrNum.length) {
        console.log(y);
        return y;
      }
      else {
        count = 0;
        z = 0;
      }
    }
  }
}
smallestCommons([23, 18]);
0
Nasko

Vous avez peut-être initialement eu un dépassement de pile à cause d’une faute de frappe: vous avez basculé entre min et minn au milieu de repeatRecurse (vous l’auriez intercepté si repeatRecurse n’avait pas été défini dans la fonction externe). Ceci étant corrigé, repeatRecurse(1,13,13) renvoie 156.

La solution évidente pour éviter un débordement de pile consiste à transformer une fonction récursive en une fonction non récursive. Vous pouvez accomplir cela en faisant:

function repeatRecurse(min, max, scm) {
    while ( min < max ) {
        while ( scm % min !== 0 ) {
            scm += max;
        }
        min++;
    }
}

Mais peut-être pouvez-vous voir l’erreur à ce stade: vous ne vous assurez pas que scm est toujours divisible par les éléments qui précédaient min. Par exemple, repeatRecurse(3,5,5)=repeatRecurse(4,5,15)=20. Au lieu d'ajouter max, vous souhaitez remplacer scm par son plus petit multiple commun par min. Vous pouvez utiliser le gcd de rgbchris (pour les entiers, !b est la même chose que b===0). Si vous souhaitez conserver l’optimisation de la queue (même si je ne pense pas qu’un moteur javascript ait une optimisation de la queue), vous obtiendrez:

function repeatRecurse(min, max, scm) {
    if ( min < max ) {
        return repeatRecurse(min+1, max, lcm(scm,min));
    }
    return scm;
} 

Ou sans la récursion:

function repeatRecurse(min,max,scm) {
    while ( min < max ) {
        scm = lcm(scm,min);
        min++;
    }
    return scm;
}

Ceci est essentiellement équivalent à la solution de rgbchris. Une méthode plus élégante peut être diviser pour régner:

function repeatRecurse(min,max) {
    if ( min === max ) {
        return min;
    }
    var middle = Math.floor((min+max)/2);
    return lcm(repeatRecurse(min,middle),repeatRecurse(middle+1,max));
}

Je recommanderais de s’éloigner de l’argument initial en présentant un tableau de deux nombres. D'une part, cela finit par vous amener à parler de deux tableaux différents: [min,max] et du tableau d'intervalle. D'autre part, il serait très facile de passer un tableau plus long et de ne jamais se rendre compte que vous avez mal agi. Il faut également plusieurs lignes de code pour déterminer le minimum et le maximum, alors que ceux-ci auraient dû être déterminés par l’appelant.

Enfin, si vous travaillez avec de très grands nombres, il peut être préférable de trouver le plus petit multiple commun en utilisant la factorisation première des nombres.

0
Teepeemm

Que diriez-vous: 

// Euclid Algorithm for the Greatest Common Denominator
function gcd(a, b) {
    return !b ? a : gcd(b, a % b);
  }
  // Euclid Algorithm for the Least Common Multiple

function lcm(a, b) {
    return a * (b / gcd(a, b));
  }
  // LCM of all numbers in the range of arr = [a, b];

function smallestCommons(arr) {
  var i, result;
  // large to small - small to large
  if (arr[0] > arr[1]) {
    arr.reverse();
  } // only happens once. Means that the order of the arr reversed.
  for (i = result = arr[0]; i <= arr[1]; i++) { // all numbers up to arr[1] are arr[0].
    result = lcm(i, result); // lcm() makes arr int an integer because of the arithmetic operator.
  }
  return result;
}
smallestCommons([5, 1]); // returns 60

0
Maria Campbell
function smallestCommons(arr) {
  var sortedArr = arr.sort(); // sort array first
  var tempArr = []; // create an empty array to store the array range
  var a = sortedArr[0];
  var b = sortedArr[1];
  for(var i = a; i <= b; i++){
    tempArr.Push(i);
  }
  // find the lcm of 2 nums using the Euclid's algorithm
  function gcd(a, b){
    while (b){
      var temp = b;
      b = a % b;
      a = temp;
    }
    return a;
  }

  function lcm(a, b){
    return Math.abs((a * b) / gcd(a, b));
  }
  var lcmRange = tempArr.reduce(lcm);


  return lcmRange;
}
0
Fadyboy

Bien joué sur la solution. Je pense que j'en ai un qui pourrait être un peu plus court juste pour référence future

function LCM(arrayRange) {
    var newArr = [];

    for (var j = arrayRange[0]; j <= arrayRange[1]; j++){
        newArr.Push(j);
    }

    var a = Math.abs(newArr[0]);
    for (var i = 1; i < newArr.length; i++) {
        var b = Math.abs(newArr[i]),
            c = a;

        while (a && b) {
            a > b ? a %= b : b %= a;
        }
        a = Math.abs(c * newArr[i] / (a + b))
    }
   return console.log(a);
}

LCM([1,5]);
0
TrojanMorse
function smallestCommons(arr) {
    let smallest, biggest, min;
    arr.reduce(function (a, b) {
        biggest = Math.max(a, b);
    });
    const max = biggest;
    arr.reduce(function (a, b) {
        smallest = Math.min(a, b);
        min = smallest;
    });
    check: while (true) {
        biggest += max;
        for (min = smallest; min < max; min++) {
            if (biggest % min != 0) {
                continue check;
            }
            if (min == (max - 1) && biggest % min == 0) {
                console.warn('found one');
                return biggest;
            }
        }
    }
}
0
Wes

    function smallestCommons(arr) {
      let min = Math.min(arr[0], arr[1]);
      let max = Math.max(arr[0], arr[1]);
      let scm = max;

      //calc lcm of two numbers:a,b;
      const calcLcm = function(a, b) {
        let minValue = Math.min(a, b);
        let maxValue = Math.max(a, b);
        let lcm = maxValue;
        while (lcm % minValue !== 0) {
          lcm += maxValue;
        }
        return lcm;
      }

      //calc scm in range of arr;
      for (let i = max; i >= min; i--) {
        scm = calcLcm(scm, i);
      }
      console.log(scm);
      return scm;
    }

    smallestCommons([1, 13]);

0
yz_n
function range(min, max) {
  var arr = [];
  for (var i = min; i <= max; i++) {
    arr.Push(i);
  }
  return arr;
}

function gcd (x, y) {
  return (x % y === 0) ? y : gcd(y, x%y);
}

function lcm (x, y) {
  return (x * y) / gcd(x, y); 
}

function lcmForArr (min, max) {
  var arr = range(min, max);
  return arr.reduce(function(x, y) {
    return lcm(x, y); 
  });
}

range(10, 15); // [10, 11, 12, 13, 14, 15]
gcd(10, 15); // 5
lcm(10, 15); // 30
lcmForArr(10, 15); //60060
0
Islam Ibakaev
    /*Function to calculate sequential numbers 
in the range between the arg values, both inclusive.*/
    function smallestCommons(arg1, arg2) {
     
       if(arg1>arg2) { // Swap arg1 and arg2 if arg1 is greater than arg2
          var temp = arg1;
          arg1 = arg2;
          arg2 =temp;
        }
      
      /*
      Helper function to calculate greatest common divisor (gcd)
      implementing Euclidean algorithm */
      function gcd(a, b) {
      	return b===0 ? a : gcd(b, a % b); 
       }
      
      /*
      Helper function to calculate lowest common multiple (lcm) 
of any two numbers using gcd function above */
       function lcm(a,b){
          return (a*b)/gcd(a,b);
         }
      
      var total = arg1; // copy min value
      for(var i=arg1;i<arg2;i++){
          total = lcm(total,i+1);
         }
      //return that total
      return total;
    }
    /*Yes, there are many solutions that can get the job done.
    Check this out, same approach but different view point.
    */
    console.log(smallestCommons(13,1)); //360360
0
Bamtak