I'm having trouble optimizing the Project Euler problem number 23 :
A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.
A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.
As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest number that can be written as the sum of two abundant numbers is 24. By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any further by analysis even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.
Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers.
Here's some explanation of my code :
First we find and store all possible abundant numbers below 28123 because the maximum integer we are going to look for is 28123. It could be a little bit better if we write 28123 - 12 because that's the biggest combination we need to get anyway but I left it with 28123 so it's more readable.
private const int max = 28123;
List<int> AbundantNumbers = new List<int>();
for (int i = 12; i <= max; i++)
{
int abudantNumber = GetProperDivisor(i);
if (abudantNumber > i)
{
AbundantNumbers.Add(i);
}
}
This is the method that returns the sum of all proper divisor of the current number :
private static int GetProperDivisor(int input)
{
int sum = 1;
for (int i = 2; i <= input / 2; i++)
{
if (input%i == 0)
{
sum += i;
}
}
return sum;
}
Next we create a List
that will hold our valid numbers (numbers that cant be written as sum of 2 abundant numbers)
List<int> results = new List<int>();
Next we have our algorithm that will determine whether a number can be written as sum of 2 abundant numbers :
for (int i = 1; i < max; i++)
{
GetAbundantNumbers(i, AbundantNumbers);
int count = allAbundantNumbers.Count(t => i != t);
if (count == allAbundantNumbers.Count)
{
results.Add(i);
}
}
It will loop through all possible integers 1 - 28123 and check which one is valid by constantly updating the list allAbundantNumbers
with new values, but only the ones that were previously not added, using the method GetAbundantNumbers
:
private static void GetAbundantNumbers(int input, IList<int> inputArray)
{
int ending = inputArray.IndexOf(input);
if (ending == -1)
{
return;
}
for (int i = ending; i < ending + 1; i++)
{
for (int j = 0; j < ending + 1; j++)
{
if (!allAbundantNumbers.Contains(inputArray[i] + inputArray[j]))
{
allAbundantNumbers.Add(inputArray[i] + inputArray[j]);
}
}
}
}
What we are doing here is we take the current integer as parameter (input
) and we check if it's in the allAbundantNumbers
list. If it's there we take the index of that, else we return that means we have already checked that number so no need of double checking. If we haven't met that number yet we start looping and add all possible sum's of that number and the previous abundant numbers.
for (int i = ending; i < ending + 1; i++)
{
for (int j = 0; j < ending + 1; j++)
{
if (!allAbundantNumbers.Contains(inputArray[i] + inputArray[j]))
{
allAbundantNumbers.Add(inputArray[i] + inputArray[j]);
}
}
}
After we have updated our list of abundant numbers sums we count from how much sums the current integer is different :
int count = allAbundantNumbers.Count(t => i != t);
If it's different than all of the current values we add it to the list of valid results :
if (count == allAbundantNumbers.Count)
{
results.Add(i);
}
That's how the code works, it gives the correct result, however it's really slow, I'm looking forward for any refactoring/optimizations concerning the overall performance of the code also any code style errors should be noted. Here's the full code :
internal class Program
{
private const int max = 28123;
private static readonly List<int> allAbundantNumbers= new List<int>();
private static void Main()
{
List<int> AbundantNumbers = new List<int>();
for (int i = 12; i <= max; i++)
{
int abudantNumber = GetProperDivisor(i);
if (abudantNumber > i)
{
AbundantNumbers.Add(i);
}
}
List<int> results = new List<int>();
for (int i = 1; i < max; i++)
{
GetAbundantNumbers(i, AbundantNumbers);
int count = allAbundantNumbers.Count(t => i != t);
if (count == allAbundantNumbers.Count)
{
results.Add(i);
}
}
Console.WriteLine(results.Sum());
Console.ReadKey();
}
private static void GetAbundantNumbers(int input, IList<int> inputArray )
{
int ending = inputArray.IndexOf(input);
if (ending == -1)
{
return;
}
for (int i = ending; i < ending + 1; i++)
{
for (int j = 0; j < ending + 1; j++)
{
if (!allAbundantNumbers.Contains(inputArray[i] + inputArray[j]))
{
allAbundantNumbers.Add(inputArray[i] + inputArray[j]);
}
}
}
}
private static int GetProperDivisor(int input)
{
int sum = 1;
for (int i = 2; i <= input / 2; i++)
{
if (input%i == 0)
{
sum += i;
}
}
return sum;
}
}