求解最大质因数

分类: 365beat怎么下载 发布时间: 2025-08-08 16:58:29
作者: admin 阅读: 3745 | 点赞: 307
求解最大质因数

最大质因数

顾名思义,对于一个自然数n,它的所有是质数的因数中,最大的那个就是n的最大质因数。本文讨论如何求解一个数的最大质因数。

算法思想

对于一个数n,我们可以用k = 2,3,4,5…这样的数来尝试整除它。对于每一个k,如果它可以整除n,就令n = n / k,一直到k不能再整除n为止。

按照上述方法,最终一定会有一个数k使得n / k = 1,这个k就是我们要求解的最大质因数。

要正确的使用这个算法,理解它的原理是非常重要的。

正确性证明

首先需要了解这一点:任何合数都可以拆分成若干个质数的积。

做一个简单的证明:对于一个自然数n,它可以写成它的最大质因数a和另一个数b的乘积。即:n = a * b,其中b可能为合数也可能为质数。

如果b为质数,那么由于a是最大质因数,所以一定有b < a(否则b是一个更大的质因数,与a是最大质因数矛盾)。

如果b为合数,那么对于b一定会有相似的拆分。即b可以拆分为它的最大质因数c与另一个数d的乘积。即:b = c * d,同理,d可以为质数也可以为合数。显然,有c < a,因为c为b的质因数,b是n的因数,所以c也是n的质因数,那么c自然小于n的最大质因数a。

那么对于d可以再分吗?答案是肯定的,并且一直分下去,我们最后要分的数一定可以写成两个质数的乘积。因为我们发现不能确定是合数还是质数的数,即b、d这一类数,如果他们是合数,那么一定是越分越小的。每一次拆分保证它会变小!但是合数终归是有下界的,所以最后那个不能确定是合数还是质数的数一定是个质数。

经过这样一个类似于递归的过程,我们最终将n分为了最大质因数与若干个质数相乘的形式。所以让k从2开始递增,从小的因数开始剔除,最终剩下的那个因数就是最大质因数。

你可能会有疑惑:k = 2,3,4,5…但是4并不是质数啊?没错,但是这并不妨碍什么。事实上,k为合数的时候一定不会被n整除(注意n在程序中是变化的)。因为k如果是合数,它一定会被它的质因数(比它小)筛去。

再回顾一下,用k剔除因数的过程中,n也是在改变的(n /= k)。最终得到的k满足条件n / k = 1。之后n = n / k = 1。

这时的k一定是个质数,因为它没有被它之前的任何一个数给分解掉。如果k是一个合数,那么它一定会被它之前的某个数分解掉。并且k也是质因数中最大的,因为k是递增的。

代码实现

// 求m的最大质因数

long long m = 600851475143;

int k = 2; //即算法中描述的k

while (m > 1){

if (m % k == 0){

m /= k;

}

else{

++k; // k是递增的

}

}

//最终令m = 1的k就是最大质因数

cout << k << endl;

可以对代码进行改良。由于我们主要是用质数来筛除小的因数,让k以1为步长进行递增主要是为了省略求质数的工作。

容易发现所有的质数中只有2是偶数。所以我们可以对k = 2的情况进行单独处理,之后k = 3,以2为步长递增,即k += 2.

long long n = 600851475143;

// 对k = 2进行单独处理

while (n > 1)

{

if (n % 2 == 0)

n /= 2;

else

break;

}

// 之后k从3开始

int k = 3;

while (n > 1){

if (n % k == 0){

n /= k;

}

else{

k += 2; // 步长改为2,增加效率

}

}

cout << k << endl;

此外,根据如下事实还可以进行进一步的优化:

每个自然数最多只能有一个大于n\sqrt{n}n​的质因数。

首先要明确,只要while循环没有满足n=1的条件,就说明仍然存在一个质因数未被我们检测出来,且这个质因数一定比已检测出来的质因数大。

在逐步筛除因数的过程中,可以维护k的一个上界:n\sqrt{n}n​,一旦k超出这个上界,结合大于/sqrt(n)sqrt(n)sqrt(n)的质因数的唯一性,可以知道剩下的未检测出来的质因数一定只有一个!那么这个质因数就是答案。

令人兴奋的是,这个质因数就是n本身!可以简单证明一下:令该质因数为x,假设这个质因数x不是n,那么一定存在另一个数a与这个质因数x相乘等于n,即:a * x = n。由于x > n\sqrt{n}n​,可知a < x,那么a应该在x之前被筛除掉才是,所以这样的一个a事实上是不存在的。所以假设不成立,即x = n。

附上代码:

long long n = 600851475143;

while (n % 2 == 0)

{

n /= 2;

}

int k = 3;

int maxFactor = sqrt(n);

while (n > 1 && k <= maxFactor)

{

if (n % k == 0)

{

n /= k;

maxFactor = sqrt(n);

}

else

{

k += 2;

}

}

if (n > 1)

k = n;

cout << k << endl;