找到两个数字的公约数的最有效方法,最多为 10^6
Posted
技术标签:
【中文标题】找到两个数字的公约数的最有效方法,最多为 10^6【英文标题】:Most efficient way to find the common divisors of two numbers upto 10^6 【发布时间】:2016-11-02 08:37:55 【问题描述】:我想存储从 1 到 10^6 的所有数字的所有除数。但这似乎太慢了。这是我的代码的 preprocess() 函数:
for(int i=1; i<=1000000; i++)
for(int j=1; j<=i/2; j++)
if(i%j==0)
divi[i][j] = true;
我是这样使用地图容器的:
map <int, bool> divi[1000010];
然后我试图找到两个给定数字的公约数。
preprocess();
int T, A, B;
cin >> T;
while(T--)
cin >> A >> B;
int common = 0;
for(it = divi[A].begin(); it!=divi[A].end(); it++)
if(divi[B][it->first]==true)
common++;
cout << common << endl;
我现在应该如何接近以使其足够快?
【问题讨论】:
看Euclidean_algorithm 请注意,divi[B][it->first] == true
将创建一个新的映射条目(如果不存在)。这会变得非常昂贵,尤其是对于素数。
顺便说一句,std::map <int, bool>
可能会被 std::set<int>
替换。
通过使用 sieve 方法,您可以摆脱预处理器方法中的模和除法。
筛法的主要优点是不用检查所有元素,模和除法几乎和乘法一样快。
【参考方案1】:
除了使用 std::map
本身会很昂贵(你不能使用数组吗?)之外,快速的数字胜利是只上升到内部循环中数字的平方根。
for (int j = 1; j * j <= i; j++)
(注意对j
求平方比计算i
的平方根更便宜,并且让您远离浮点计算。)
这必须同时注意如果j
是一个除数,那么i / j
也是一个除数。所以你也需要更换
divi[i][j] = true;
与
divi[i][j] = divi[i][i / j] = true;
此优化以单个数的除数计算为中心。有更快的方法来获取一组 数字的除数,但我的方法可能就足够了。如果没有,请投反对票。
【讨论】:
【参考方案2】:这取决于您想要什么:如果您只想要某些特定数字的公约数,那么欧几里得算法就是解决方案。
如果您真的想要所有数字 1..n 的所有除数的列表,一种解决方案是(类似于筛子):
for(int I=1;I<=sqrt(n);++I)
for(int j=I;j*I<=n;++j) divi[I*j][j]=divi[I*j][I]=true;
原来的代码复杂度是O(N^2),第一个答案是O(N^1.5)。我相信新公式是 O(N*log N)
【讨论】:
当然你也可以用 I*I以上是关于找到两个数字的公约数的最有效方法,最多为 10^6的主要内容,如果未能解决你的问题,请参考以下文章
检查具有数字和字符数据的 2 个数据帧之间差异的最有效方法?
从包含 10 亿个整数的文件中显示前 100 个整数的最有效方法。内存最多可容纳 100 万个整数