如何找到一系列数字中最不常见的倍数?

时间:2015-07-08 19:34:08

标签: javascript function math recursion

给定一个包含两个数字的数组,让它们定义一系列数字的开头和结尾。例如,[2,6]表示范围2,3,4,5,6。我想编写javascript代码来查找范围的最小公倍数。我的代码仅适用于小范围,而不适用于[1,13](范围1,2,3,4,5,6,7,8,9,10,11,12,13),导致堆栈溢出。如何有效地找到范围的最小公倍数?

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

26 个答案:

答案 0 :(得分:35)

我认为这可以完成工作。

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

答案 1 :(得分:5)

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

答案 2 :(得分:2)

范围[a,b]的LCM函数

// Partially specialize Helper
template <typename T>
class Helper<NiceA, T>
{
  static void bar();
};

// Now implement the member function
template <typename T>
void Helper<NiceA, T>::bar()
{
}

答案 3 :(得分:2)

由于这个问题最近已经恢复,因此我认为这是一个更简单的解决方法,编写非常简单的辅助函数来计算两个整数的最大公因数(gcd),以计算最小公因数两个整数的倍数(lcm,用于计算整数数组(lcmAll)的最小公倍数,生成两个给定整数(rng)之间的整数范围,以及最后,在我们的main函数中,计算两个给定整数(lcmRng)之间整数范围的最小公倍数:

const gcd = (a, b) => b == 0 ? a : gcd (b, a % b)
const lcm = (a, b) =>  a / gcd (a, b) * b
const lcmAll = (ns) => ns .reduce (lcm, 1)
const rng = (lo, hi) => [...Array (hi - lo + 1)] .map ((_, i) => lo + i)

const lcmRng = (lo, hi) => lcmAll (rng (lo, hi))

console .log (lcmRng (1, 13))

所有这些功能都很简单。尽管该问题被标记为递归,但只有gcd是递归的。如果这是尝试使用递归的方法,我们可以使用类似以下内容的递归方式重写lcmAll

const lcmAll = (ns) => 
  ns.length == 0 
    ? 1 
    : lcm(ns[0], lcmAll(ns .slice (1)))

尽管我非常喜欢递归,但没有其他理由选择reduce上的递归版本。在这种情况下,reduce会更干净。

最后,如果您真的希望API最初请求在数组中传递范围边界的位置,则可以再编写一个包装器:

const leastCommonMultiple = ([lo, hi]) => lcmRng (lo, hi)

leastCommonMultiple ([1, 13]) //=> 360360

答案 4 :(得分:2)

我不像其他答案那样花哨,但我认为这很容易阅读。

&#13;
&#13;
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.
&#13;
&#13;
&#13;

编辑:将答案转换为摘录。

答案 5 :(得分:1)

这是原始方法的非递归版本。

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

答案 6 :(得分:1)

嘿,我遇到了这个页面并希望分享我的解决方案:)

&#13;
&#13;
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]);
&#13;
&#13;
&#13;

答案 7 :(得分:0)

这是另一个非递归的for-loop解决方案

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

答案 8 :(得分:0)

function smallestCommons(arr) {
    let min = Math.min(...arr);
    let max = Math.max(...arr);
    let rangArr = [];
    for(let i = min; i <= max; i++) rangArr.push(i);
    let smallestCommon = max;
    while(!rangArr.every(e => smallestCommon % e === 0)){
        smallestCommon += max;
    }
    return smallestCommon;
}


console.log(smallestCommons([1, 13]));

答案 9 :(得分:0)

我在 typescript 中做了一个类似的函数,它执行相同的任务,但只是没有递归......

function findLowestCommonMultipleBetween(start: number, end: number): number {
  let numbers: number[] = [];

  for (let i = start; i <= end; i++) {
    numbers.push(i);
  }

  for (let i = 1; true; i++) {
    let divisor = end * i;

    if (numbers.every((number) => divisor % number == 0)) {
      return divisor;
    }
  }
}

答案 10 :(得分:0)

我认为它会起作用。

 var a = [2, 6];
    
    function getTotalX(a) {
      var num = 1e15;
      var i; 
      var arr = [];
      for (i = 1; i <=num ; i++){
        arr.push(i);
      }
     
      for (i = 0; i < a.length; i++){
        var filterArr = arr.filter((val, ind, arr) => (val % a[i] === 0));
      }
      
     console.log(filterArr[0]); // will return 6
      
    }

答案 11 :(得分:0)

我还发现自己正在freeCodeCamp JavaScript Certification上应对这一挑战。这就是我想出的:

function smallestCommons(arr) {

    let newArr = [];
  
    // create a new array from arr [min, min + 1,......., max - 1, max]
    for (let i = Math.min(...arr); i <= Math.max(...arr); i++){
      newArr.push(i);
    }
  
    // let the max of newArr be the smallestCommonMultiple initially
    let largest = Math.max(...newArr);
    let smallestCommonMultiple = largest;
    
    // If the supposedly smallestCommonMultiple fail on any of elements in 
    //newArr add the max element until we find the smallestCommonMultiple. 
    while (newArr.some(element => smallestCommonMultiple % element !== 0)){
      smallestCommonMultiple += largest; 
    }
  
    return smallestCommonMultiple; 
 }
 
 console.log(smallestCommons([23, 18]));

答案 12 :(得分:0)

当我想出用两个数字来做到这一点的最佳方法时,我发现其他答案有些令人困惑,所以我发现在Wikipedia上找到了最佳的解决方案。

https://en.wikipedia.org/wiki/Least_common_multiple#Calculation

查找两个数字的最小公倍数的最有效方法是SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); boolean isChecked = sharedPreferences.getBoolean("play_music", false); if(isChecked) {AudioPlay.resumeAudio(); AudioPlay.mediaPlayer.setLooping(true);} else {AudioPlay.pauseAudio();}

为此,我们需要计算最大公分母。最有效的方法是使用Euclid算法。

https://en.wikipedia.org/wiki/Greatest_common_divisor#Euclid's_algorithm

这是两个数字的完整解决方案,以防其他人遇到此问题,但只需要计算两个数字即可:

(a * b) / greatestCommonDivisor(a, b);

答案 13 :(得分:0)

我使用es6功能的解决方案是

给定数字的Lcm

  const gcd = (a, b) => (!b ? a : gcd(b, a % b));

  const lcm = (a, b) => a * (b / gcd(a, b));

  const getLcm = (arr) => {

    const numbers = arr.sort((a, b) => parseInt(a) - parseInt(b));

    let result = parseInt(numbers[0]);

    for (let i = 1; i < numbers.length; i++) {
      result = lcm(parseInt(result), parseInt(numbers[i + 1]));
    }

    return result;
  };

给定数字的Hcf

  const getHcf = (arr) => {

    const numbers = arr.sort((a, b) => parseInt(a) - parseInt(b));

    let result = parseInt(numbers[0]);

    for (let i = 1; i < numbers.length; i++) {
      result = gcd(parseInt(numbers[i]), parseInt(result));
    }

    return result;
  };

像这样打电话

  console.log(getLcm([20, 15, 10, 40])). Answer 120

  console.log(getHcf([2, 4, 6, 8, 16])). Answer 2

答案 14 :(得分:0)

这是另一种非常简单的方法,具有较低的复杂性。

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;
}

答案 15 :(得分:0)

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

答案 16 :(得分:0)

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;
            }
        }
    }
}

答案 17 :(得分:0)

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;
}

答案 18 :(得分:0)

这是我的解决方案。我希望你会发现它很容易理解:

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;
}

答案 19 :(得分:0)

    /*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

答案 20 :(得分:0)

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.

答案 21 :(得分:0)

怎么样:

&#13;
&#13;
// 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
&#13;
&#13;
&#13;

答案 22 :(得分:0)

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

答案 23 :(得分:0)

由于输入错误,您最初可能有堆栈溢出:您在g++ -IextB main.cpp -LextB -lB -o main 的中间切换minminn(如果repeatRecurse,您会发现错误}没有在外部函数中定义)。修复后,repeatRecurse返回156。

避免堆栈溢出的明显答案是将递归函数转换为非递归函数。您可以通过执行以下操作来实现:

repeatRecurse(1,13,13)

但也许你现在可以看到错误:你不能确保function repeatRecurse(min, max, scm) { while ( min < max ) { while ( scm % min !== 0 ) { scm += max; } min++; } } 仍然可以被scm之前的元素整除。例如,min。您希望将repeatRecurse(3,5,5)=repeatRecurse(4,5,15)=20替换为max的最小公倍数,而不是添加scm。你可以使用rgbchris的gcd(对于整数,min!b是一样的)。如果你想保持尾部优化(虽然我不认为任何javascript引擎有尾部优化),你最终会得到:

b===0

或没有递归:

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

这基本上等同于rgbchris的解决方案。更优雅的方法可能是分而治之:

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

我建议远离原始参数,即两个数字的数组。首先,它最终导致您谈论两个不同的数组: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)); } 和范围数组。另一方面,通过一个更长的阵列很容易,从来没有意识到你做错了什么。它还需要几行代码来确定最小值和最大值,这些应该由调用者确定。

最后,如果您要使用真正的大数字,最好使用数字的素数因子化来找到最小公倍数。

答案 24 :(得分:0)

很好地解决了这个问题。我想我有一个可能缩短的时间只是为了将来的参考,但不好看看你的

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

答案 25 :(得分:0)

 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(leastCommonMultiple([1,13]))