简体   繁体   中英

Is there a known fast algorithm for finding all pairs of numbers that multiply to a given number?

For example, the pairs that multiple to 16 are {(16,1), (2,8), (4,4)} and the pairs that multiply to 15 are {(15,1), (5,3)} but I'm not of how to construct an algorithm better than brute force. My method looks like

    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);
        }
    }

which is sloppy and probably not as efficient as possible.

Here's a sample method for you, though I'm not sure if it's the "most efficient one", per se:

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);
    }
}

Using C#7 tuple return syntax because I can. :P

EDIT: Switched from a for loop to a while loop to handle the case for when m <= 2 .

EDIT 2: As suggested by Adwaenyth, this is a midified version of the method that checks if m is even. If not, then skip all even potential factors. Also, as suggested by other answers, limit the iteration to the square root of m instead of 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;
    }
}

I'm pretty sure that this is as efficient as this particular approach can go. To make it better, you would tweak it to check against all prime numbers and their multiples up to the square root of m . Ideally, you would do this against a look-up table, since a lot of the time you save by only comparing prime numbers would be lost while generating them. (For really large m s, it still comes out faster, though.)

EDIT 3 I discovered that my previous code's use of lastVal was making the required time be a bit inconsistent as well as introducing a weird bug that made it sometimes forget to check larger factors. Here's an update that should fix those problems:

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;
    }
}

First generate a list of primes up to the square root of input N you will have, for each prime p check if it divides N. If it does then N = N/p and repeat this recursively until all primes in list has have been exhausted or N/p = 1.

In the rare case of where no primes in list can divide the input, then your number is a prime. The only pairs are {(1, N), (N, 1)}. This should get more rare as your input increases exponentially.

For the other case count all the prime divisors and the times they occur. Finally find all combination of products of the primes up to square root of N, which will all be part of pairs that divide N.

I think that the best way to do this is perform prime factorization algorithm. But you should note that it is very difficult area of mathematics. You can find articles in http://mathworld.wolfram.com/PrimeFactorizationAlgorithms.html

From sequence of prime numbers you can combine all possible pairs which form given number

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM