是否有已知的快速算法来查找乘以给定数字的所有数字对?

时间:2017-05-19 05:13:30

标签: c# algorithm

例如,16的倍数为{(16,1), (2,8), (4,4)}的对和15倍的对是{(15,1), (5,3)},但我不知道如何构造算法比蛮力好。我的方法看起来像

    private static IEnumerable<Tuple<int, int>> Multipliers(int m)
    {
        var found = new HashSet<int>();
        foreach(int v in Enumerable.Range(1, m))
        {
            int d = m / v;
            bool even = m % v == 0;
            if(even && found.Contains(d))
            {
                yield return Tuple.Create(d, v);
            }
            found.Add(v);
        }
    }

这是草率的,可能没有那么高效。

3 个答案:

答案 0 :(得分:2)

这里有一个示例方法,但我不确定它是否是最有效的一个&#34;本身:

public static IEnumerable<(int A, int B)> Multipliers(int m)
{
    yield return (m, 1);

    int i = 2;
    int lastVal = m / 2;
    while (i <= lastVal)
    {
        if (m % i == 0)
        {
            lastVal = m / i;
            yield return (lastVal, i);
        }

        i++;
    }
}

public static void Main(string[] args)
{
    foreach (var pair in Multipliers(16))
    {
        Console.WriteLine("{0}, {1}", pair.A, pair.B);
    }
}

使用C#7元组返回语法,因为我可以。 :P

编辑:从for循环切换到while循环以处理m <= 2时的情况。

编辑2:正如Adwaenyth所建议的,这是一种中等版本的方法,用于检查m是否均匀。如果没有,那么跳过所有可能的因素。此外,正如其他答案所建议的那样,将迭代限制为m而不是m/2的平方根:

public static IEnumerable<(int A, int B)> Multipliers(int m)
{
    yield return (m, 1);

    int lastVal = (int)Math.Sqrt(m);
    int increment = (m % 2 == 0) ? 2 : 1;
    int i = (m % 2 == 0) ? 3 : 2;

    while (i <= lastVal)
    {
        if (m % i == 0)
        {
            lastVal = m / i;
            yield return (lastVal, i);
        }

        i += increment;
    }
}

我非常确定这和这种特殊方法一样有效。为了使它更好,你可以调整它以检查所有素数及其倍数,直到m的平方根。理想情况下,您可以针对查找表执行此操作,因为在生成它们时,通过仅比较素数而节省的大量时间将会丢失。 (对于非常大的m,它仍然会更快出现。)

编辑3 我发现我之前的代码使用lastVal使得所需的时间有点不一致,并且引入了一个奇怪的错误,使其有时会忘记检查更大的因素。这是一个应该解决这些问题的更新:

public static IEnumerable<(int A, int B)> Multipliers(int m)
{
    yield return (m, 1);

    int finalVal = (int)Math.Sqrt(m);
    int increment = m % 2 == 0 ? 2 : 1;
    int i = m % 2 == 0 ? 3 : 2;

    while (i <= finalVal)
    {
        if (m % i == 0)
        {
            yield return (m / i, i);
        }

        i += increment;
    }
}

答案 1 :(得分:0)

首先生成一个素数列表,直到输入N的平方根,对于每个素数p检查它是否除N.如果确实那么N = N / p并递归地重复这个,直到列表中的所有素数都有已经筋疲力尽或N / p = 1。

在罕见的情况下,列表中没有素数可以划分输入,那么您的数字是素数。唯一的对是{(1,N),(N,1)}。当您的输入呈指数级增长时,这种情况会变得更加罕见。

对于另一个案例,计算所有主要除数及其出现的次数。最后找到素数的所有组合,直到N的平方根,这将是除N的对的一部分。

答案 2 :(得分:0)

我认为执行此操作的最佳方法是执行素数分解算法。但是你应该注意到这是一个非常困难的数学领域。您可以在http://mathworld.wolfram.com/PrimeFactorizationAlgorithms.html

中找到文章

从素数序列中,您可以组合形成给定数字的所有可能对