-4

I was asked this question in interview. Output of below algorithm is perfectly fine, but it's very slow for larger input parameters. How can we improve it's performance without changing calculation logic?

    public static int SomeAlgo(int n)
    {
        if ((n == 0) || (n == 1))
        {
            return n;
        }
        else
        {
            return SomeAlgo(n - 1) + SomeAlgo(n - 2);
        }
   }

It become very slow starting from parameter value 40. I'm using below code to check time taken to execute:

static void Main(string[] args)
{
    var watch = System.Diagnostics.Stopwatch.StartNew();

    Console.WriteLine("Algo Output: " + SomeAlgo(40));

    watch.Stop();
    var elapsedMs = watch.ElapsedMilliseconds;
    Console.WriteLine("Time taken in ms: " + elapsedMs);
    Console.ReadLine();
}
aditya
  • 57
  • 1
  • 8
  • 1
    I'm voting to close this question as off-topic because it is about reviewing existing, working code. This question may be on-topic on Code Review: https://codereview.stackexchange.com/ – Camilo Terevinto Jun 02 '18 at 19:41
  • @Fabio Well... yeah. Edited that :) – Camilo Terevinto Jun 02 '18 at 19:44
  • Here's a C question with the same problem: https://stackoverflow.com/questions/29882155/improve-c-fibonacci-series – Lasse V. Karlsen Jun 02 '18 at 19:47
  • It is **fibonacci** series. google for it – Eser Jun 02 '18 at 19:52
  • But I actually would like to know why it gets slow. 40 should not be a problem, even before christ... – modmoto Jun 02 '18 at 20:00
  • 2
    The explanation for why it is slow is that to evaluate 40, it has to evaluate 38 and 39. To evaluate 38, it has to evaluate 36 and 37, and so on. However, when it then finally gets back to 39, it has to evaluate 37 and 38, both of which has been evaluated once, and this overlap just explodes as it gets down to the lower numbers. For instance, `SomeAlgo(1)` has been called 102.334.155 times, that is over 102 million times. – Lasse V. Karlsen Jun 02 '18 at 20:05

1 Answers1

-1

Due to recursion function executes multiple times for most of the input values, so best solution I can think of is storing the output values to avoid repeated calculations:

static Dictionary<int, int> results = new Dictionary<int, int>();
public static int SomeAlgo(int n)
{
    int result = 0;

    if (results.TryGetValue(n, out result))
    {
        return result;
    }

    if ((n == 0) || (n == 1))
    {
        return n;
    }

    result = SomeAlgo(n - 1) + SomeAlgo(n - 2);
    results.Add(n, result);
    return result;
}

It made huge difference in performance. edit: Thanks for comment by Lasse Vågsæther Karlsen, found this technique is called Memoization.

aditya
  • 57
  • 1
  • 8
  • This solution puts the whole concept of `Recursion` under question. Instead, you'd better research about how recursion deals with the stack and what makes it different from a for/while loop. That said; try to figure out where recursion would be more useful than a loop. – Transcendent Jun 02 '18 at 19:54
  • @Transcendent Actually, that is a completely valid way to optimize a recursive function with dynamic programming techniques. A better way would be to rewrite the method to avoid the recursive principle altogether, which is possible for this particular method, but if you can't do that, caching recursive call results is perfectly valid. – Lasse V. Karlsen Jun 02 '18 at 20:08
  • If you see this article - https://www.geeksforgeeks.org/program-for-nth-fibonacci-number/ - the answer here is basically just method 2, use dynamic programming. – Lasse V. Karlsen Jun 02 '18 at 20:10
  • @LasseVågsætherKarlsen: That applies to situation/environments where there's no for/while loop. For example Haskell, else it would not make much sense. – Transcendent Jun 02 '18 at 20:11
  • There are definitely better ways to solve this, specially with using mathematical formulas. But since I was asked in interview to not modify calculation logic, so so far it seems to be best solution. – aditya Jun 02 '18 at 20:14
  • @aditya: By converting it to a for loop, the calculation logic would remain untouched. You should not do `2+2=5` then minus that by 1 to correct it. – Transcendent Jun 02 '18 at 20:17