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.