How to find the least common multiple of a range of numbers?

前端 未结 14 1660
一个人的身影
一个人的身影 2020-12-08 08:32

Given an array of two numbers, let them define the start and end of a range of numbers. For example, [2,6] means the range 2,3,4,5,6. I want to write javascrip

相关标签:
14条回答
  • 2020-12-08 09:01

    You may have originally had a stack overflow because of a typo: you switched between min and minn in the middle of repeatRecurse (you would have caught that if repeatRecurse hadn’t been defined in the outer function). With that fixed, repeatRecurse(1,13,13) returns 156.

    The obvious answer to avoiding a stack overflow is to turn a recursive function into a non-recursive function. You can accomplish that by doing:

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

    But perhaps you can see the mistake at this point: you’re not ensuring that scm is still divisible by the elements that came before min. For example, repeatRecurse(3,5,5)=repeatRecurse(4,5,15)=20. Instead of adding max, you want to replace scm with its least common multiple with min. You can use rgbchris’s gcd (for integers, !b is the same thing as b===0). If you want to keep the tail optimization (although I don’t think any javascript engine has tail optimization), you’d end up with:

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

    Or without the recursion:

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

    This is essentially equivalent to rgbchris’s solution. A more elegant method may be divide and conquer:

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

    I would recommend moving away from the original argument being an array of two numbers. For one thing, it ends up causing you to talk about two different arrays: [min,max] and the range array. For another thing, it would be very easy to pass a longer array and never realize you’ve done something wrong. It’s also requiring several lines of code to determine the min and max, when those should have been determined by the caller.

    Finally, if you’ll be working with truly large numbers, it may be better to find the least common multiple using the prime factorization of the numbers.

    0 讨论(0)
  • 2020-12-08 09:02
    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
    
    0 讨论(0)
提交回复
热议问题