Pollard's Rho Algorithm 教程
[前言]
一般而言, 实现分解质因数有两种方式 :
(1). 用筛法 预处理每个数的最小质因子 ,从而在 的时间内完成单次分解。 此算法的空间复杂度是 的。
(2). 枚举 到 中每个数 , 进行试除法。 此算法的时间复杂度为 , 而空间复杂度为 。
可以看出这两种做法的时间复杂度开支都太大了。 而本文介绍的 Pollard's Rho Algorithm 可以在
( 表示求最大公约数的复杂度) 的时间内 , 花费 空间完成找出给定数 的一个非平凡因子 。
[前置内容]
在理解 Pollard's Rho Algorithm 的原理之前 , 首先我们需要了解以下知识 :
Miller-Rabin 素数测试 :
如何判断一个数是质数? 最朴素的方法是 : 枚举 到 中每个数 , 判断其是否是 的约数。 但这样的时间复杂度达到了 。 我们有更优的做法 :
首先 , 根据费马小定理 , 若 是质数 , 那么对于 , 有
我们还知道若 是质数 , 且 , 那么 或 中必有一式成立。这是因为 可以推出 。
那么我们就得到了一个判定方法 : 对于要判断的数 , 选取一底数 满足 , 判断引理 或 是否成立。 若不成立直接得到 是合数 , 接着反复验证引理 是否成立 (若指数 是奇数,且 , 就可以将 变为 )。
这样单次测试的错误率是 ,然而通过选取多个不同的底数 , 可以将错误率降低至 。
具体而言 , 对于 , 选取前十二个质数作为底数即可达到 的正确率。
此算法将时间复杂度提高至最劣情况下 。
生日悖论 :
我们知道, 在中国大多数高中 , 每个班有 到 位同学。 你的班级是否有两个有缘人是同年同月同日生呢? 这样的概率是很大的 , 由下图就可以知晓。
(此图来源为 Wikipedia)
事实上,我们可以用函数表示 个人生日两两不同的概率 :
当 时 , 存在两人生日相同的概率就达到了 。 这也对应了上图。
弗洛伊德判环法 :
我们来解决一个这样的问题 : 有一个伪随机数列 和随机函数 , 其递推公式为 。这个序列存在一个循环节 , 请给出循环开始的第一个位置 和环长 。
解决这个问题最简单的方法是用平衡树 / 哈希表判断每个数是否在之前出现过了,这样的时间复杂度是 的。 并且花费了 的空间。而弗洛伊德的方法是 : 用两个指针,一个指针每次走一步,另一个每次走两步, 如果两个指针指向的数对应值相同 , 那么就找到了一个或若干个循环 , 在这个基础上可以轻松得到 与 的具体值。简而言之 , 就是需要找到第一个 满足 。
我们分析此做法的时间复杂度 : 对于任意 满足 ,都有 。 由 可以推得 , 。 因此我们找到的 事实上是第一个 满足 。
因此此算法时间复杂度是 的。 并且空间复杂度只有 。
Richard P. Brent 教授对这个算法做了一些常数优化。 思路是 : 每次走 的次幂步 , 直到发现循环为止。 这个优化使我们可以直接找到 的精确值。根据他本人的试验, 此做法将 Pollard's Rho Algorithm 的运行效率提高约 。
[算法流程]
我们已经了解了上述知识 , 下面回归问题本身 , 如何快速分解质因数?
首先用 Miller-Rabin 素数测试判断 是否是质数。
然后 , 一个简单思路是 , 若我们能找到 ( 和 是 的非平凡因子) , 便可以将 和 递归地继续分解下去。
不妨构造伪随机数列 , 其中 ( 为一常数)。 而另一个数列 客观存在 ,由生日悖论我们可知 的的循环节是 级别的 , 而 的循环节长度是 级别的。
假设存在两个位置 使得 且 , 取 , 就得到 的一个非平凡因子。
因此我们要做的其实是找出 的循环节 , 不妨使用弗洛伊德判环法 ,计算 。
若 , 那么将 加一
若 , 说明 和 同时在两个数列的循环节上。 需要调整随机函数 。
否则直接返回 。
因此我们期望用 个 分解出 的一个非平凡因子。 Pollard's Rho Algorithm 算法分解一个因子的复杂度是 的。
事实上 , 可以继续优化
我们拟定一个参数 ,计算每 个 的乘积对 取模的结果 。
若 ,则说明这 个 与 的 gcd 均为 1 。
若 ,那么我们就找到了 的一个非平凡因子
否则,即 ,我们不知道此时我们是否需要重新进行算法,需要回到 次操作之前。
故算法产生一次有效的分解的期望时间复杂度被优化至了 。
下面是 Pollard's Rho Algorithm 的一个演示图 , 相信会有助于您更好地理解。 来源为 Wikipedia
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现