Problem #104 says:
Given that F(k) is the first Fibonacci number for which the first nine digits AND the last nine digits are 1-9 pandigital, find k.
First of all the Fibonacci number F(k) is some 68 thousand digits long. It’s insane to try to and brute force this using a big int class and a couple of variables; and it only gets worse if one tries to use a recursive algorithm. Even if you use some caching of previous Fibonacci terms the program still won’t get close to the answer before running out of memory.
So how can we solve this? Well consider what we need to look at; the first and last 9 digits. Which means of some 68 thousand digits we care about 18 of them so why bother calculating the rest? To do this for the last 9 digits should be pretty obvious. If we have the two previous Fibonacci numbers that are added to get the next Fibonacci number what we can do is only remember the Fibonacci number mod one billion. This will chop off all the numbers except for the last few which is what we want. We can then use a long data type to store and calculate the Fibonacci series (or at least the last couple of digits of it).
How then do we get the first couple of digits to check that? We can use a formula called Binet’s formula.
\[F(n) = \frac{\Phi^{n}-(1-\Phi)^{n}}{\sqrt{5}}\]
This helps because we only need to give it the k term we’re looking for and it will give back the first digits of the term F(k) without calculating the intervening terms. We modify it a bit to fit into c#/mono data types (basically we use it log base ten) with some other magic built it.
So the solution is provided below in c#/mono developed in monodevelop; runs in about 2 seconds.
using System;
using System.Linq;
namespace Problem104
{
class MainClass
{
public static void Main (string[] args)
{
long fnm2 = 1L;
long fnm1 =1L;
long fn = 0L;
decimal k = 2;
bool found = false;
while (!found)
{
k++;
fn = fnm2 + fnm1;
if (CheckBottomDigits(fn))
{
if (CheckTopDigits(k))
found = true;
}
fnm2 = fnm1 % 1000000000;
fnm1 = fn % 1000000000;
if (k % 500 == 0)
Console.WriteLine(k);
}
Console.WriteLine(k);
}
public static decimal philog10 = decimal.Parse("0.2089876402499787");
public static decimal sqrt5log10 = decimal.Parse("-0.349485002168009");
public static bool CheckTopDigits (decimal n)
{
decimal td = (n * philog10) + sqrt5log10;
double t = Math.Pow(10,(double)(td - (int)td + 8));
if (t.ToString().Length < 9)
return false;
if (PanDigital(t.ToString().Substring(0,9)))
return true;
else
return false;
}
public static bool CheckBottomDigits (long check)
{
string num = check.ToString();
if ( num.Length >= 9)
{
if (PanDigital(num.Substring(num.Length - 9,9)))
return true;
}
return false;
}
public static bool PanDigital (string num)
{
bool pan = true;
if (!num.Contains('1'))
pan = false;
if (!num.Contains('2'))
pan = false;
if (!num.Contains('3'))
pan = false;
if (!num.Contains('4'))
pan = false;
if (!num.Contains('5'))
pan = false;
if (!num.Contains('6'))
pan = false;
if (!num.Contains('7'))
pan = false;
if (!num.Contains('8'))
pan = false;
if (!num.Contains('9'))
pan = false;
return pan;
}
}
}