深入算法: 如何快速求一个数的所有因子数?
如何编写一个求一个数所有因子的程序呢? 假设这个数是2000, 相信大家很快就可以写出如下代码:
上面程序可以正确地得出答案,该程序的时间复杂度为O(n), 2000次循环对cpu来说也只是几毫秒的事情,但如果将 n 扩大为一个16位的整数, 计算机就可能要算上一天了。。。
如何进行优化呢,这就要开始研究因子数的数学性质了! 下面我们就来从0开始证明一个数与其因子数存在什么性质:
先假设自然数 , 我们要求出它所有因子的集合
,我们需要证明两个命题成立即可:
命题1: 因子是成对出现的: 如果 自然数 存在一个因子
, 那么必然存在另一个因子
使得
(注意这里如果 N 是平方数的话
可以等于
)。
证明: 已知 , 要证明该命题成立我们只需证明
即可, 由
, 我们知 N 可以分解成一个数字
和另一个数字
, 又因为
, 所以
。
题外话: 上述证明只是从直观上来出发,如何用反证法来证明呢,可以先假设另一个数字 不能整除 N, 那么最后会推出
是不能整除 N 的, 而与条件
产生矛盾, 所以
一定会整除
.
(这个方法的证明思路就放在这里了,过程交给读者了)
命题2:因数是成对出现的(上面已证明),一个小于等于算数平方根,另外一个大于等于算数平方根
证明: 我们利用反证法证明简单地这个命题,假设我们找到了一个因子 小于
, 如果存在另一个因子
也小于
, 那么
, 那么 因子
与其成对的因子必然不是
。假设我们找到了一个因子
大于
, 如果存在另一个因子
也大于
, 那么
, 那么因子 与其成对的因子必然不是
。 所以一对因子唯一的可能就是一个小于等于
,另外一个大于等于
。
最后我们来证明等于的情况, 我们只需要找到 一个因子 x1 = x2, 使得 x1 * x2 = N, 这只有 N 是平方数的情况下成立。
那么我们就可以开始写代码了,由命题2可以得到,由于因子都是成对出现的我们只需要循环到 就可以找到所有因子了!
那么我们就把该算法从时间复杂度O(n) 优化到 O()了: