【问题标题】:JavaScript - Improving algorithm for finding square roots of perfect squares without Math.sqrtJavaScript - 改进算法以在没有 Math.sqrt 的情况下找到完美平方的平方根
【发布时间】:2016-06-21 17:09:43
【问题描述】:

我正在尝试从零开始学习算法和编码。我写了一个函数,它只会找到平方数的平方根,但我需要知道如何提高它的性能并可能返回非平方数的平方根

function squareroot(number) {
    var number;
    for (var i = number; i >= 1; i--) {
        if (i * i === number) {
            number = i;
            break;
       }
   }
   return number;
}

 alert(squareroot(64))

将返回 8

最重要的是,我需要知道如何提高这种性能。我还不太关心它的有限功能

【问题讨论】:

  • squareroot(65) 会发生什么?提示:没什么好说的。
  • `我需要知道如何提高它的性能`是什么让你认为它没有“好”的性能?你的基准是什么?人们谈论性能的一般术语,但仅此而已。你想改进什么?
  • var squareroot = Math.sqrt; 我帮你搞定了
  • 看来我正在遍历每一个可能的数字,这可能是不必要的
  • pretty many quite sophisticated algorithms to do this。不过,作为学习者,您不会从其中的大部分内容中受益。

标签: javascript algorithm square-root


【解决方案1】:

这是我可以建议的一个小改进。首先 - 从 0 开始迭代。其次 - 当根候选的平方超过 number 时退出循环。

function squareroot(number) {
    for (var i = 0; i * i <= number; i++) {
        if (i * i === number)
            return i;
   }
   return number; // don't know if you should have this line in case nothing found
}

与初始 O(n) 相比,此算法将在 O(√number) 时间内工作,这确实是您要求的性能改进。

编辑#1

更有效的解决方案是按照@Spektre 的建议对答案进行二进制搜索。已知 x2 是增函数。

function squareroot(number) {
    var lo = 0, hi = number;
    while(lo <= hi) {
         var mid = Math.floor((lo + hi) / 2);
         if(mid * mid > number) hi = mid - 1;
         else lo = mid + 1;
    }
    return hi;
}

此算法的运行时间复杂度为 O(log(number))

【讨论】:

  • @user5680735 这在O(n) 中运行,如果您稍微更改一下以扫描从MSB 到LSB 的位,您将获得在O(log(n)) 中运行的二进制搜索。代码会略有变化,请参阅我链接的 QA 我评论了您的问题
  • @Spektre,您在哪里找到了sqrt 函数用法?我已经更改了 O(sqrt(number)) 表示法,以免让您感到困惑。
  • 对不起,我的错...你说得对。我早上还没有喝茶...我在O(sqrt(number))看到它错过了O:)
  • @LeoDutra 你是对的,2 不是 5 的平方根。但是 OP 有兴趣找到平方数的平方根。 5 不是平方数。
【解决方案2】:

您尝试做的事情称为numerical methods。求解方程的最基本/最简单的数值方法(是的,你在这里求解方程x^2 = a)是Newtons method

你所做的就是迭代这个方程:

在你的情况下是f(x) = x^2 - a,因此是f'(x) = 2x

这将允许您以任何精度找到任何数字的平方根。不难增加一个近似整数解的步骤,验证是否sol^2 == a

【讨论】:

  • 感谢您的回答。但是a 是什么?我在维基百科牛顿方法页面的 preudocode 中发现 f = @(x) x^2 - 2 %The function whose root we are trying to find 并且无法理解为什么 ... - 2 在这里
  • @Mikhail a 是您要查找的平方根数。所以如果你想找到一个sqrt(15),那么a=15
【解决方案3】:

将牛顿法与要逼近的函数分开。可用于查找其他根。

function newton(f, fPrime, tolerance) {
  var x, first;

  return function iterate(n) {
    if (!first) { x = n; first = 1; }

    var fn = f(x);

    var deltaX = fn(n) / fPrime(n);
    if (deltaX > tolerance) {
      return iterate(n - deltaX)
    }

    first = 0;
    return n;
  }
}


function f(n) { 
  return  function(x) { 
    if(n < 0) throw n + ' is outside the domain of sqrt()';
    return x*x - n;
  };
}

function fPrime(x) {
  return 2*x;
}


var sqrt = newton(f, fPrime, .00000001)
console.log(sqrt(2))
console.log(sqrt(9))
console.log(sqrt(64))

【讨论】:

    【解决方案4】:

    二分搜索效果最好。

    let number = 29;
    let res = 0;
    
    console.log((square_root_binary(number)));
    function square_root_binary(number){
    
        if (number == 0 || number == 1)  
           return number;
    
        let start = 0;
        let end = number;
    
    
        while(start <= end){
    
            let mid = ( start + end ) / 2;
    
            mid = Math.floor(mid);
    
            if(mid * mid == number){
                return mid;
            }
    
            if(mid * mid < number){
                start = mid + 1;
                res = mid;
            }
            else{
                end = mid - 1;
            }
        }
    
        return res;
    }
    

    【讨论】:

      【解决方案5】:
      function squareRoot(n){
          var avg=(a,b)=>(a+b)/2,c=5,b;
          for(let i=0;i<20;i++){
              b=n/c;
              c=avg(b,c);
          }
          return c;
      }
      

      这将通过重复求平均值返回平方根。

      var result1 = squareRoot(25) //5
      var result2 = squareRoot(100) //10
      var result3 = squareRoot(15) //3.872983346207417
      

      JSFiddle:https://jsfiddle.net/L5bytmoz/12/

      【讨论】:

      • 你能解释一下你的功能吗?
      • 我也想知道函数的解释。为什么要保留 c = 5 的值以及为什么要保留 i&lt;20,我的意思是为什么不保留 21 或为什么不保留 19。
      【解决方案6】:

      这是使用牛顿迭代法的解决方案 -

      /**
       * @param {number} x
       * @return {number}
       */
      // newstons method
      var mySqrt = function(x) {
          if(x==0 || x == 1) return x;
      
          let ans, absX = Math.abs(x);
          let tolerance = 0.00001;
          while(true){
              ans = (x+absX/x)/2;
              if(Math.abs(x-ans) < tolerance) break;
              x = ans;
          }
          return ans;
      };
      

      【讨论】:

        【解决方案7】:

        我在 Github 上看到了这个解决方案,这是在不使用任何外部库的情况下获取数字的平方根的更好和最简单的方法

        function TakingPerfectSquare(Num) {
           for (var i = 0; i <= Num; i++) {
              var element = i;
              if ((element == element) && (element*element == Num)) {
                 return true;
              }
           }
           return false;
        }
        console.log(TakingPerfectSquare(25));
        

        【讨论】:

        • element == element 是做什么的?不是一直都是true吗?
        【解决方案8】:

        如果你用正方形分析所有自然数,你可能会发现一个规律......

        Numbers   Squares   Additives
           1         1          3
           2         4          5
           3         9          7
           4        16          9
           5        25         11
           6        36         13
           7        49         15
        

        查看正方形列中的第一行(即 1)并将其与添加剂列中的第一行(即 3)相加。您将得到四个,它们位于正方形列的第二行。

        如果你不断重复这一点,你会发现这适用于所有自然数的平方。现在,如果您查看添加剂列,下面的所有数字实际上都是奇数。

        要找到完美平方的平方根,您应该继续用连续的奇数(从 1 开始)减去它,直到它为零。可以减去的次数是该数字的平方根。

        这是我在打字稿中的解决方案...

        function findSquareRoot(number: number): number {
          for (let i = 1, count = 0; true; number -= i, i += 2, count++) {
            if (number <= 0) {
              return number === 0 ? count : -1; // -1 if number is not a perfect square
            }
          }
        }
        

        希望这有更好的时间复杂度:)

        【讨论】:

        • 我没有检查你的代码是否有效,但推理是合理的。但是,通过 2 迭代仍然是 O(N),而二进制搜索是 O(log(N))。
        猜你喜欢
        • 1970-01-01
        • 2016-09-26
        • 2020-09-26
        • 2023-01-29
        • 1970-01-01
        • 2014-03-26
        • 1970-01-01
        • 2019-11-23
        相关资源
        最近更新 更多