找到两个数字的公约数的最有效方法,最多为 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 &lt;int, bool&gt; 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-&gt;first] == true 将创建一个新的映射条目(如果不存在)。这会变得非常昂贵,尤其是对于素数。 顺便说一句,std::map &lt;int, bool&gt; 可能会被 std::set&lt;int&gt; 替换。 通过使用 sieve 方法,您可以摆脱预处理器方法中的模和除法。 筛法的主要优点是不用检查所有元素,模和除法几乎和乘法一样快。 【参考方案1】:

除了使用 std::map 本身会很昂贵(你不能使用数组吗?)之外,快速的数字胜利是只上升到内部循环中数字的平方根。

for (int j = 1; j * j &lt;= 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的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中查找数字的所有因数的最有效方法是啥?

检查具有数字和字符数据的 2 个数据帧之间差异的最有效方法?

从包含 10 亿个整数的文件中显示前 100 个整数的最有效方法。内存最多可容纳 100 万个整数

找到与给定数字相乘的数字的有效方法

在 SQL 中找到两个集合的最紧凑和最有效的方法是啥? [复制]

算法课最多约数问题