繁体   English   中英

如何在 JavaScript 中找到 integer 的质因数?

[英]How can I find the prime factors of an integer in JavaScript?

我试图找到一个数字的质因数,在 javascript 中使用 for 循环在下面记录为“整数”。我似乎无法让它工作,我不确定它是我的 JavaScript 还是我的计算逻辑。

 //integer is the value for which we are finding prime factors var integer = 13195; var primeArray = []; //find divisors starting with 2 for (i = 2; i < integer/2; i++) { if (integer % i == 0) { //check if divisor is prime for (var j = 2; j <= i / 2; j++) { if (i % j == 0) { isPrime = false; } else { isPrime = true; } } //if divisor is prime if (isPrime == true) { //divide integer by prime factor & factor store in array primeArray integer /= i primeArray.push(i); } } } for (var k = 0; k < primeArray.length; k++) { console.log(primeArray[k]); }

上面的答案效率低下,复杂度为 O(N^2)。 这是 O(N) 复杂度的更好答案。

 function primeFactors(n) { const factors = []; let divisor = 2; while (n >= 2) { if (n % divisor == 0) { factors.push(divisor); n = n / divisor; } else { divisor++; } } return factors; } const randomNumber = Math.floor(Math.random() * 10000); console.log('Prime factors of', randomNumber + ':', primeFactors(randomNumber).join(' '))

您可以根据需要过滤重复项!

这是一个有效的解决方案:

 function getPrimeFactors(integer) { const primeArray = []; let isPrime; // Find divisors starting with 2 for (let i = 2; i <= integer; i++) { if (integer % i !== 0) continue; // Check if the divisor is a prime number for (let j = 2; j <= i / 2; j++) { isPrime = i % j !== 0; } if (!isPrime) continue; // if the divisor is prime, divide integer with the number and store it in the array integer /= i primeArray.push(i); } return primeArray; } console.log(getPrimeFactors(13195).join(', '));

你走在正确的轨道上。 有两个小错误。 integer - 1的评估似乎不正确。 我相信更合适的评估是<= integer外部for循环中的<= integer 这是因为当您将整数除以低于integer /= i ,这会导致最终的整数评估为29 在这种情况下,最终的素数除数也是29 ,因此需要将其评估为<=< integer - 1

至于为什么最终的日志语句不起作用,有一个与primeArray[k]primeArray[i]的简单拼写错误。

我确实相信上面的两个代码都存在错误。 如果将整数替换为 100,素数分解将不再起作用,因为因子 2 不能与 for 循环一起考虑。 由于 j = 2,i = 2 且 j<=i/2 在条件中 - 这意味着循环永远不会在 i=2 时运行,这是一个主要因素。

试图让它以这种方式工作,但无法弄清楚。

不得不依赖一种不同的方法,这里有一个 while 循环:

    function getAllFactorsFor(remainder) {
    var factors = [], i;

    for (i = 2; i <= remainder; i++) {
        while ((remainder % i) === 0) {
            factors.push(i);
            remainder /= i;
        }
    }

    return factors;
}

https://jsfiddle.net/JamesOR/RC7SY/

你也可以用这样的东西:

let findPrimeFactors = (num) => {
    let arr = [];


    for ( var i = 2; i < num; i++) {
        let isPrime
        if (num % i === 0) {
            isPrime = true;
            for (var j = 2; j <= i; j++) {
                if ( i % j === 0) {
                isPrime == false;
                }
            } 
        }if (isPrime == true) { arr.push(i)}

    }console.log(arr)
}

findPrimeFactors(543)

我刚开始使用 JavaScript,但在从事具有类似目标的学校项目时,我设法为此提出了自己的解决方案。

唯一的问题是大数需要很长时间,效率不高。 但它完美地工作。

function isPrime(n){
if (n === 1){
  return false;
}
  else if (n === 2){
    return true;
  }
  else{
  for (let x = 2; x < n; x ++){
    if (n % x === 0){
      return false;
    }
  }
    return true;
}
}

let primeFac = []
let num = 30
for (let x = 0; x <= num; x++){
  if (num % x === 0 && isPrime(x) === true){
primeFac.push(x);
  }
}
console.log(`${primeFac}`)

如果您从底部开始工作,则无需检查任何以下因素是否为素数。 这是因为任何较低的素数都已经被除掉了。

 function getPrimeFactorsFor(num) { const primes = []; for (let factor = 2; factor <= num; factor++) { while ((num % factor) === 0) { primes.push(factor); num /= factor; } } return primes; } console.log("10 has the primes: ", getPrimeFactorsFor(10)); console.log("8 has the primes: ", getPrimeFactorsFor(8)); console.log("105 has the primes: ", getPrimeFactorsFor(105)) console.log("1000 has the primes: ", getPrimeFactorsFor(1000)) console.log("1155 has the primes: ", getPrimeFactorsFor(1155))

将整数 ( n ) 分解为其质因数时,在找到第一个质因数后,手头的问题就简化为找到商 ( q ) 的质因数分解。

假设n可被p1整除,那么我们有n = p1 * q1因此在找到p1 ,问题就简化为分解q1 (商)。 如果函数名称是primeFactorizer那么我们可以递归调用它, n解决方案是:

n = p1 * primeFactorizer(q1)

n = p1 * p2 * primeFactorizer(q2)

...

直到qn本身就是素数。

此外,我将使用辅助生成器函数为我们生成素数:

function * primes () {
  let n = 2
  while (true) {
    let isPrime = true
    for (let i = 2; i <= n / 2; i++) {
      if (n % i === 0) {
        isPrime = false
        break
      }
    }
    if (isPrime) {
      yield n
    }
    n++
  }
}

分解n函数是:

function primeFactorizer (n, result = []) {
  for (const p of primes()) {
    if (n === p) {
      result.push(p)
      return result
    }
    if (n % p === 0) {
      result.push(p)
      return primeFactorizer(n / p, result)
    }
  }
}

我们只需一个循环就可以找到最多 n 的质因数。 这是一个非常简单的解决方案,没有任何嵌套循环。


时间复杂度将小于 O(n),因为我们将“n”除以“i”。

function primeFactors(n) {
    let arr=[];
    let i = 2;
    while(i<=n){
        if(n%i == 0) {
            n= n/i;
            arr.push(i);
        } else {
            i++;
        }
    }
    return arr;
}
// primeFactors(10) [2,5]
// primeFactors(10) [2,2,5,5]
// primeFactors(2700) [2, 2, 3, 3, 3, 5, 5]

这是另一种寻找素数因子的实现,有三种变体。 它比其他实现更有效,最坏的情况是sqrt(n) ,因为它更早停止。

function*表示它是一个生成器函数 因此,返回的是生成器而不是数组,并且仅在请求时才计算下一个素数因子。

// Example: 24 -> 2, 3
function* singlePrimeFactors (n) {
    for (var k = 2; k*k <= n; k++) {
        if (n % k == 0) {
            yield k
            do {n /= k} while (n % k == 0)
        }
    }
    if (n > 1) yield n
}

// Example: 24 -> 2, 2, 2, 3
function* repeatedPrimeFactors (n) {
    for (var k = 2; k*k <= n; k++) {
        while (n % k == 0) {
            yield k
            n /= k
        }
    }
    if (n > 1) yield n
}

// Example: 24 -> {p: 2, m: 3}, {p: 3, m: 1}
function* countedPrimeFactors (n) {
    for (var k = 2; k*k <= n; k++) {
        if (n % k == 0) {
            var count = 1
            for (n /= k; n % k == 0; n /= k) count++
            yield {p: k, m: count}
        }
    }
    if (n > 1) yield {p: n, m: 1}
}

// Test code
for (var i=1; i<=100; i++) {
    var single = JSON.stringify(Array.from(singlePrimeFactors(i)))
    var repeated = JSON.stringify(Array.from(repeatedPrimeFactors(i)))
    var counted = JSON.stringify(Array.from(countedPrimeFactors(i)))
    console.log(i, single, repeated, counted)
}

// Iterating over a generator
for (var p of singlePrimeFactors(24)) {
    console.log(p)
}

// Iterating over a generator, an other way
var g = singlePrimeFactors(24)
for (var r = g.next(); !r.done; r = g.next()) {
    console.log(r.value);
}

我的解决方案避免返回非主要因素:

let result = [];
let i = 2;
let j = 2;
let number = n;

for (; i <= number; i++) {
    let isPrime = number % i === 0;
    if (isPrime) {
        result.push(i);
        number /= i;
    }
    while (isPrime) {
        if (number % i === 0) {
            result.push(i);
            number /= i;
        } else {
            isPrime = false;
        }
    }
}

return result;

有了上面这么多好的解决方案,想通过在数学论坛中使用这个定理来做一点改进, 通过取平方根找到素因数

 function primeFactors(n) { // Print the number of 2s that divide n while (n%2 == 0) { console.log(2); n = n/2; } // n must be odd at this point. So we can skip // one element (Note i = i +2) for (var i = 3; i <= Math.sqrt(n); i = i+2) { // While i divides n, print i and divide n while (n%i == 0) { console.log(i); n = n/i; } } // This condition is to handle the case when n // is a prime number greater than 2 if (n > 2) console.log(n); } primeFactors(344); console.log("--------------"); primeFactors(4); console.log("--------------"); primeFactors(10);

希望这个答案增加价值。

这是使用递归的解决方案

function primeFactors(num, primes){
  let i = 2;
  while(i < num){
    if(num % i === 0){
      primes.push(i);
      return primeFactors(num/i, primes);
    }
    i++
  }
  primes.push(num);
  return primes;
}

console.log(primeFactors(55, []))
console.log(primeFactors(15, []))
console.log(primeFactors(40, []))
console.log(primeFactors(13, []))
// [ 5, 11 ]
// [ 3, 5 ]
// [ 2, 2, 2, 5 ]
// [ 13 ]

当我试图简化我在这里看到的几个解决方案时,我偶然发现了这个解决方案。 虽然它不检查除数是否是素数,但它似乎可以工作,但我用其他数字对其进行了测试,但我无法解释这是怎么可能的。

function start() {

  var integer = readInt("Enter number: ");
  println("The prime factorization is: ");

  for(var i = 2; i <= integer; i++) {
    if (integer % i == 0) {
        println(i);
        integer = integer / i;
        i = i - 1;
    }
  }
}

我用yield检查了算法,但这比递归调用慢很多。

function rootnth(val, power=2) {
let o = 0n; // old approx value
let x = val;
let limit = 100;
let k = BigInt(power);

while(x**k!==k && x!==o && --limit) {
  o=x;
  x = ((k-1n)*x + val/x**(k-1n))/k;
}

return x;

}

// Example: 24 -> 2, 2, 2, 3
function repeatedPrimeFactors (n,list) {
if (arguments.length == 1) list = "";

if (n % 2n == 0) return repeatedPrimeFactors(n/2n, list + "*2")
else if (n % 3n == 0) return repeatedPrimeFactors(n/3n, list + "*3")
var sqrt = rootnth(n);
let k = 5n;

while (k <= sqrt) {
    if (n % k == 0) return repeatedPrimeFactors(n/k, list + "*" + k)
    if (n % (k+2n) == 0) return repeatedPrimeFactors(n/(k+2n), list + "*" + (k+2n))
    k += 6n;
}
list = list + "*" + n;
return list;

}

var q = 11111111111111111n;  // seventeen ones
var t = (new Date()).getTime();
var count = repeatedPrimeFactors(BigInt(q)).substr(1);
console.log(count);
console.log(("elapsed=" + (((new Date()).getTime())-t)+"ms");

在这里,我尝试使用因子 2 和 3,然后交替添加 2 anf 4 (5,7,11,13,17,...) 直到数字的平方根。 17 个(不是质数)大约需要 1 秒,而 19 个(质数)需要 8 秒(Firefox)。

随着时间的推移,我已经改进了这个功能,试图尽可能快地获得它(与我在网上找到的其他功能竞争,还没有找到一个运行速度始终比它更快的功能)。

function primFact(num) {
  var factors = [];
  
  /* since 2 is the only even prime, it's easier to factor it out 
   * separately from the odd factor loop (for loop doesn't need to 
   * check whether or not to add 1 or 2 to f).
   * The condition is essentially checking if the number is even 
   * (bitwise "&" operator compares the bits of 2 numbers in binary  
   * and outputs a binary number with 1's where their digits are the 
   * same and 0's where they differ. In this case it only checks if 
   * the final digit for num in binary is 1, which would mean the 
   * number is odd, in which case the output would be 1, which is 
   * interpreted as true, otherwise the output will be 0, which is 
   * interpreted as false. "!" returns the opposite boolean, so this 
   * means that '!(num & 1)' is true when the num is not odd)
   */
  while (!(num & 1)) {  
    factors.push(2);
    num /= 2;
  }
  
  // 'f*f <= num' is faster than 'f <= Math.sqrt(num)'
  for (var f = 3; f*f <= num; f += 2) {
    while (!(num % f)) { // remainder of 'num / f' isn't 0
      factors.push(f);
      num /= f;
    }
  }
  
  /* if the number is already prime, then this adds it to factors so
   * an empty array isn't returned
   */
  if (num != 1) {
    factors.push(num);
  }
  return factors;
}

与我运行它的函数相比,这在大量数字上表现得非常好,尤其是当数字是素数时,(当我在OneCompiler等在线编译器中运行它时,运行速度很少低于 10 毫秒)所以如果你想要速度d 说这是一个很好的方法。

仍在努力使其更快,但在不添加新条件进行检查的情况下包含所有素数的唯一方法是迭代所有奇数。

如果有人正在寻找最快的解决方案,这里有一个基于我的库prime-lib 的解决方案。 它可以在 1 毫秒内计算 2 到 2^53 - 1 之间的任何数字的质因数。 函数源代码可在此处获得

import {primeFactors} from 'prime-lib';

const factors = primeFactors(600851475143);
//=> [71, 839, 1471, 6857]

这是使用过滤器方法的嵌套函数的解决方案。

 function primeFactors(params) { function prime(number) { for (let i = 2; i < number + 1; ) { if (number === 2) { return true; } if (number % i === 0 && number !== i) { return false; } else if (i < number) { i++; } else { return true; } } } let containerPrime = []; let containerUnPrime = []; for (let i = 0; i < params; i++) { if (prime(i)) { containerPrime.push(i); } else { containerUnPrime.push(i); } } return containerPrime.filter((e) => params % e === 0); } console.log(primeFactors(13195));

 function primeFactorization(n) { let factors = []; while (n % 2 === 0) { factors.push(2); n = n / 2; } for (let i = 3; i <= Math.sqrt(n); i += 2) { while (n % i === 0) { factors.push(i); n = n / i; } } if (n > 2) { factors.push(n); } return factors; } console.log(primeFactorization(100));

O(sqrt(n)) 复杂度的答案,它比 O(n) 更快:

 const number = 13195; let divisor = 2; const result = []; let n = number; while (divisor * divisor <= number) { if (n % divisor === 0) { result.push(divisor); n /= divisor; } else { divisor++; } } if (n > 1) { result.push(n); } console.log(result);

上面的代码(具有 while 循环的代码)是正确的,但该代码中有一个小的更正。

var num, i, factorsArray = [];

function primeFactor(num) {
  for (i = 2; i <= num; i++) {
    while (num % i == 0) {
      factorsArray.push(i);
      num = num / 2;
    }
  }
}
primeFactor(18);
var newArray = Array.from(new Set(factorsArray));
document.write(newArray);

这是我的解决方案

function prime(n) {

    for (var i = 1; i <= n; i++) {

        if (n%i===0) {
            myFact.push(i);
            var limit = Math.sqrt(i);

            for (var j = 2; j < i; j++) {

                if (i%j===0) {
                    var index = myFact.indexOf(i);

                    if (index > -1) {
                        myFact.splice(index, 1);
                        } 
                } 
            }
        }
    }
}
var n = 100, arr =[],primeNo = [],priFac=[];
    
    for(i=0;i<=n;i++){
        arr.push(true);
    }
    //console.log(arr)
    let uplt = Math.sqrt(n)
    for(j=2;j<=uplt;j++){
        if(arr[j]){
            for(k=j*j;k<=n;k+=j){
                arr[k] = false;
            }
            
        }
    }
    
    for(l=2;l<=n;l++){
        if(arr[l])
        primeNo.push(l)
        
    }
    for(m=0;m<primeNo.length;m++){
        if(n%primeNo[m]==0)
        priFac.push(primeNo[m])
    }
    console.log(...priFac);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM