Introduction to the Lesson

Welcome to our hands-on lesson in which we explore the fascinating concept of recursion on practice. Throughout this lesson, we'll peel back the layers of three foundational problems - Generating the Fibonacci sequence, Finding the sum of all elements in an array, and Calculating factorials. We'll systematically deconstruct each of these problems, expose the core of each solution, and then rebuild them. If the name Fibonacci reminds you of Leonardo of Pisa (also known as Fibonacci), one of the most famous mathematicians of the Middle Ages renowned for his work on the Fibonacci sequence, you're not mistaken. Buckle up as we'll retrace this journey of Fibonacci.

Problem 1: Fibonacci Sequence

So, what is the Fibonacci sequence? The Fibonacci sequence is an infinite sequence of numbers, starting with 0 and 1, with every subsequent number being the sum of the previous two numbers: 0, 1, 1, 2, 3, 5, 8, 13, ...

Given a number n, our task is to implement a recursive algorithm that returns the n-th number in the Fibonacci sequence. Remember, indexing starts from 0, just like Python's 0-index style.

Visualizing Fibonacci might be a little bit tricky at first. If you are into art and design, you might have heard about the golden spiral, a logarithmic spiral whose growth factor is linked to the golden ratio. Interestingly, the Fibonacci sequence is connected with the golden ratio as well. If you look at the ratio of two consecutive numbers in the Fibonacci series, you'll observe that it approximates the golden ratio! It's truly fascinating to see such a foundational mathematical pattern connected to art and design.

Problem 1: Naive Recursion Approach

Here, we present a straightforward recursive method that returns the n-th Fibonacci number:

def fib(n): 
   if n <= 1: 
       return n 
   else: 
       return fib(n - 1) + fib(n - 2)

The above naive recursive solution is a clear and straightforward way, but it is incredibly inefficient. Its inefficiency arises due to repeated calculations.

This inefficiency can be seen by looking at how many times the program calculates fib(n - 2). This function is called once in the scope of fib(n) and then gets called again in the scope of fib(n - 1). This redundancy in calculations greatly bloats up the time required to execute the program, leading to this solution's inefficiency.

For instance, when calculating the 5th Fibonacci number, the 3rd Fibonacci number will be calculated twice, and the 2nd Fibonacci number will be calculated three times. You can even see that, in general, the n-th Fibonacci number will have to calculate the (n - 2)-nd Fibonacci number (n - 1) times, which is incredibly wasteful and inefficient.

In fact, this approach has an exponential time complexity of O(2n)O(2^n), which means the runtime doubles with each addition to the input size.

Ideally, we would want to reduce this to O(n)O(n), which signifies linear time complexity, a much more efficient rate. This can be achieved.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal