【问题标题】:Smallest Common Multiple - Infinite Loop最小公倍数 - 无限循环
【发布时间】:2016-05-12 19:15:46
【问题描述】:

我正在做一个名为 Smallest Common Multiplier 的 freeCodeCamp 练习。练习的目的如下:

找到所提供参数的最小公倍数 被两者均分,以及除以所有序号 这些参数之间的范围。

范围将是一个由两个数字组成的数组,这两个数字不一定是 按数字顺序排列。

例如对于 1 和 3 - 找到 1 和 3 的最小公倍数 可以被 1 到 3 之间的所有数字整除。

我想我可以通过将传递给函数的数组中的元素从小到大排序来保存它,然后使用 for 循环检查所有数字是否为number % x === 0。然后我将所有内容封装在一个检查分隔符数量的while循环中(如果分隔符的数量小于我正在检查的最高数字,请重复该过程。

看来我写了一个无限循环,导致浏览器崩溃。

function smallestCommons(arr) {

  //sort from smallest to largest
  arr.sort(function(a, b) {
    return a-b;
  });

  var result = 1;
  var divisors = [];

  //while number of divisors !== last number to check
  while(divisors.length < arr[1]) {
    //check if number divides result
    for(var x = arr[0]; x < arr[1]; x++) {
      //if it divides result
      if(result % x === 0) {
        //push it to divisors
        divisors.push(x);
      }
      else {
        //clear divisors
        divisors = [];
      }
    }
    //check next number
    result++;
  }

  return result;
}


smallestCommons([5,1]);

你能指出我做错了什么,或者指出如何进行练习吗?

【问题讨论】:

  • 我认为首先要做的是阅读如何找到两个数字的 LCM,将在软件中实现它的任务放在一边。

标签: javascript algorithm


【解决方案1】:

请注意,您在函数的 else 部分中清理了 divisors 数组。 这样你就不能通过条件divisors.length &gt;= arr[1]

但是您的 LCM 实施根本不起作用

【讨论】:

    【解决方案2】:

    这是我的 javascript 解决方案,也许你会发现它有用的参考:

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

    【讨论】:

      【解决方案3】:

      您可以将以下函数用于最小公共乘数。但是,对于更大的输入和差异,它将在一个非常大的循环中运行。

      因此,这取决于您运行代码的环境。如果您在https://jsfiddle.net/qf4snysL/ 中尝试此代码,您将获得正确的输出。但在 FCC 中,它可能会为输入 [18, 23] 提供无限循环。

      function smallestCommons(arr) {
      var range = arr.sort();
        //alert(range);
        var array = [];
        for(var i=arr[0];i<=arr[arr.length-1];i++){
        array.push(i);
        }
      var x=true;
      var LCM=0;
      while(x){
        LCM++;
        for(var j = array[0]; j <=array[array.length-1];j++){
          if(LCM % j !==0){
            break;
          }
          else if(j==array[array.length-1]){
          x=false;
          }
        }
      }
      return LCM;
      
      }
      smallestCommons([18,23]);
      
      //noprotect
      

      看看底部的//noprotect,它是有特殊用途的。

      【讨论】:

      • 这个(未注释的)代码中实现的想法是什么?它与Yup's answer 相比如何?申请一些math怎么样?
      【解决方案4】:

      许多人似乎都在为这个挑战而苦苦挣扎(我与其他人一起苦苦挣扎......),也许你们会发现我的解决方案很有帮助。其实很简单:

      // noprotect
      function smallestCommons(arr) {
      
        arr = arr.sort();
        var multiple = 0;
      
      
        function test(num) {
          for (var j = arr[0]; j<=arr[1]; j++) {
            if (num % j !== 0) return false;
          }
        return true;
        }
      
      
        for (var i = arr[1]*2; i<100000000; i++) {
          if (test(i)){
             multiple = i;
             break;
          }
        }
      
        return multiple;
      }
      

      'test' 函数测试给定数字 ('num') 是否是所提供参数的公倍数以及介于两者之间的所有数字。 for 循环遍历所有正数,直到一个数满足该测试,并返回该数作为我们的解决方案。我们可以跳过一些数字,从最大参数乘以 2 (arr[1]*2) 开始,因为最小公倍数不可能小于这个(对吗?)。但也可以从 i=1 开始。希望这会有所帮助!

      【讨论】:

        【解决方案5】:

        既然你问如何进行练习:

        回想一下,最小公倍数等于:

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

        (请参阅:Wikipedia)。 最大公约数函数gcd可以使用Euclidean algorithm实现:

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

        现在lcm 已经实现,并且使用数学上lcm(a, b, c) === lcm((lcm(a, b), c) 的事实,我们只需要一种方法来生成包含给定startend 然后reduce 的数字范围范围为它们的最小公倍数,如下所示:

        function range(start, end) {
          return [...Array(end - start + 1)].map((_, i) => start + i);
        }
        
        function smallestCommons(arr) {
          const start = Math.min(...arr);
          const end = Math.max(...arr);
        
          return range(start, end).reduce(function(a, b) {
            return lcm(a, b);
          });
        }
        

        这就结束了:

        > smallestCommons([1, 5])
        > 60
        > smallestCommons([5, 1])
        > 60
        > smallestCommons([1, 13])
        > 360360
        > smallestCommons([23, 18])
        > 6056820
        

        【讨论】:

          【解决方案6】:
          // noprotect
              function smallestCommons(arr) {
                  var value = Math.max.apply(null, arr) * Math.min.apply(null, arr) - 1;
                  var succ = false;
                  do {
                      value++;
                      for (var i = Math.min.apply(null, arr); i <= Math.max.apply(null, arr); i++) {
                          if (value % i != 0) {
                              succ = false;
                              break;
          
                          }
                          succ = true;
          
                      }
                  } while (!succ);
          
                  return value;
              }
          

          【讨论】:

          • 您应该详细说明您的答案,以便其他人了解该代码的工作方式和原因。
          【解决方案7】:

          这是解决此问题的另一种方法。多亏了 cmets,代码很容易理解。

          /**
           * Find the smallest common multiple of the provided integers
           * that can be evenly divided by both, as well as by all sequential numbers in
           * the range between these integers.
           *
           * @param arr Array containing two integers.
           * @returns The smallest common multiple.
           */
          function smallestCommons(arr) {
            let min = Math.min(arr[0], arr[1]);
            let max = Math.max(arr[0], arr[1]);
            let i = 1;
            while (!divisibleByAll(min, max, max * i)) {
              i++;
            }
            return max * i;
          }
          
          /**
           * This function checks whether c is divisible by a and b.
           *
           * @param a An integer lower than b.
           * @param b An integer greater than a.
           * @param c An integer, to check if it is divisible by a and b.
           * @returns True c is divisible by a and b, false otherwise.
           */
          function divisibleByAll(a, b, c) {
            for (let i = a; i <= b; i++) {
              if (c % i != 0) {
                return false;
              }
            }
            return true;
          }
          
          console.log(smallestCommons([1, 5])); // 60
          console.log(smallestCommons([2, 10])); // 2520
          console.log(smallestCommons([1, 13])); // 360360
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-07-11
            • 2021-07-16
            • 2020-10-12
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多