JavaScript - 改进算法,用于在没有Math.sqrt的情况下查找完美正方形的平方根

时间:2016-03-07 22:54:50

标签: javascript algorithm square-root

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

SELECT email, submited_date FROM gradbusdb.user 
WHERE submited_date BETWEEN '2016-02-01' AND '2016-02-29'
UNION
SELECT email, submited_date FROM gradedudb.user
WHERE submited_date BETWEEN '2016-02-01' AND '2016-02-29'
UNION
SELECT email, submited_date FROM gradtheologydb.user
WHERE submited_date BETWEEN '2016-02-01' AND '2016-02-29'

ORDER BY submited_date ASC

将返回8

最重要的是,我需要知道如何改善这种性能。我真的不关心它有限的功能

8 个答案:

答案 0 :(得分:3)

这是我可以建议的一个小改进。首先 - 从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建议的那样,更有效的解决方案是二元搜索答案。已知x 2 正在增加功能。

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))运行时间复杂度。

答案 1 :(得分:3)

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

你要做的就是迭代这个等式:

enter image description here

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

这将允许您以任何精度查找任意数字的平方根。添加一个将解近似于整数的步骤并验证是否sol^2 == a

并不难

答案 2 :(得分:1)

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

/**
 * @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;
};

答案 3 :(得分:0)

将牛顿方法从函数分离为近似值。可以用来寻找其他根源。

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 :(得分:0)

二进制搜索将最有效。

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 :(得分:0)

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/

答案 6 :(得分:0)

我在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));

答案 7 :(得分:0)

如果你用平方分析所有自然数,你可能会发现一个模式......

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

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