Recurrence relations are fundamental in computer science and mathematics, especially when analyzing algorithms’ time complexity. They help us understand the performance of algorithms in terms of their input size. One common technique for solving recurrences is the Master Theorem, which provides a framework for classifying and solving recurrences. However, learners often find it challenging to memorize the three cases of the Master Theorem and apply them correctly. This blog explores an alternative approach to solving recurrences using geometric series and summation bounds, eliminating the need to memorize the Master Theorem.
Before we delve into our alternative approach, let’s discuss why solving recurrences is crucial for a computer scientist. Analyzing algorithms’ time complexity helps determine our code’s efficiency. This information is vital for designing and optimizing algorithms, making it a fundamental skill for computer scientists and programmers. Many algorithms for solving various problems involve recursive strategies, and thinking of them in terms of recursion-based solutions is very natural. For a computer scientist, analyzing the bounds of these algorithms will require solving recurrences, i.e., at each step of the recurrence, we need to accumulate the cost associated with each recursive call. Generally, we calculate the cost at each level and then accumulate all these costs. Well, look at this in a while.
Here’s the general recurrence that we’re going to solve:
This can be interpreted with the following recursion tree:
Notice: We’re only looking at the recurrence cases that are solved through the Master Theorem (i.e., they can be represented in some form of geometrical series).
Geometric series: A fundamental concept#
To understand how geometric series can simplify recurrence analysis, we first have to understand the concept of the geometric series. A geometric series is a sequence of numbers in which each term after the first is found by multiplying the previous term by a fixed, nonzero number called the common ratio. The formula for the sum of a geometric series is as follows:
The two series above have a closed summation captured by the following formula:
where,
- is the sum of the series with n terms.
- is the first term.
- is the common ratio.
- is the number of terms.
There are two key insights from the geometric series formula:
- Increasing geometric series: An increasing geometric series is bounded by the last term.
- Decreasing geometric series: A decreasing geometric series is bounded by the first term.
You’re encouraged to look at the proofs of these two properties. These two properties form the basis of our new approach to solving recurrences.
Before we go into the details of solving recurrences, let’s look at some example series and establish bounds for the series using the two properties mentioned above.
Examples: Sum of the series with a specific common ratio rrr#
Let’s look at the following example:
is an example of a decreasing geometric series where is any value bigger then , with a common ratio of , and it’s bounded by .
Similarly, is an example of an increasing geometric series with a common ratio of , and it’s bounded by .
Let’s explore some further examples.
Example: Let’s explore the following example and see if it’s bound using the geometric series facts presented above.
This is an increasing geometric series that’s bounded by the last term, i.e., .
Based on the geometric series, most recurrences where the recurrence relationship expands by geometric sizes can be easily bounded asymptotically using the properties mentioned above. We’ll study them in greater detail with the help of three cases in the remainder of this blog.
In the first case, when we expand the recurrence and sum up all the costs associated at each level, it emerges as an increasing geometric series from the first to the last level. In such a case, the asymptotic bound is just the cost of the last level.
Example: Now let us look at this bound in the form of recurrences:
If we open the recurrence above mathematically, it will be something like this (for reference, look at the recurrence tree above):
If we rewrite the last equation in increasing level order, i.e., level 1’s cost first, then the second, then the third, and so on, then the rearranged equation will be as follow:
This last equation clearly depicts an increasing geometric series that is bounded by the last term. This results in the asymptotic complexity of .
As we go down the recursion tree, the size of decreases by the common ratio of therefore, the total number of levels can be seen as the size of the sequence:
Here is the number of levels, which can be calculated by solving for for the last term (which is 1, the base case):
Therefore, the number of levels is equal to . So,
Therefore, the asymptotic complexity of the recurrence is .
In case the recurrence yields an increasing geometric series, the recurrence will be bounded above the last level, i.e.,
will be bounded by .
Note: It’s interesting that the cost equals the number of nodes at the last level.
In the second case, when we expand the recurrence and sum up all the costs associated with each level, it emerges as a decreasing geometric series when we look from the first level to the last level. In such a case, the asymptotic bound is just the cost at the first level.
Example: Let’s look at another recurrence:
Let’s look at the recurrence tree of the above-mentioned recurrence:
If we open the recurrence above mathematically, it will be something like this (for reference, look at the recurrence tree above):
As we go down the recursion tree, the size of decreases by a factor of . Therefore, the total number of levels is equal to . Therefore,
If we rewrite the last equation in increasing level order, i.e., level 1’s cost first, then the 2nd, then the third, and so on, then the rearranged equation will be:
This is just a decreasing geometric series ending on , Therefore, the total bound will be , bounded by the first term.
In the third case, as we expand the recurrence, the cost remains the same on each level. Consequently, the geometric reduction in size constrains the recurrence to halt after a number of levels corresponding to
Example: Let’s look at another recurrence:
Let’s look at the recurrence tree of the recurrence above:
If we open the recurrence above mathematically, it will be something like this (for reference, look at the recurrence tree above):
If we rearrange the last equation such that level 1 is the first, level 2 is the second, and so on, the equation becomes:
As we go down the recursion tree, the size of decreases by a factor of . Therefore, the total number of levels is equal to . So, because every term in the series equation above is and there are levels, the total time complexity bound will be .
Now, in such cases of recurrences, there’s is no need to perform the complicated conversion from recurrence to series. All we need to do is look at the first level expansion of the recursion tree and see which case it fit into:
If it’s an increasing geometric series, then the last terms bound it.
If it’s a decreasing geometric series, then the first terms bound it.
If it’s equal on all levels, then the total bound is:
Let’s look at some solved examples in the slides below.
In some cases, it’s harder to see, on paper, whether the two immediate levels follow an increasing, decreasing, or equal pattern. In such cases, looking at the last level helps a lot. Here, in the following examples, we’ve demonstrated how to solve such recurrences.
It’s important to remember the following property:
Logarithm’s base disappears in Big O notation#
The logarithm function has an interesting property that, makes the base of the disappear in Big O notation:
Notice, in the above equation that, is always just a constant. Therefore, in Big O notation:
This is the reason why computer scientists seldom write the base of the logarithm.
In this blog, we explored an easy way of solving recurrences. Notably, there’s no requirement to memorize intricate formulas, such as the Master Theorem, for resolving these recurrences. What’s particularly advantageous is that understanding this method not only simplifies our approach to problem-solving but also serves as a reminder that geometric series feature prominently in algorithmic designs. Consequently, we can regard them as a fundamental element in algorithmic thinking, particularly for pruning and searching strategies. For more in-depth insights, feel free to delve into the details provided in the accompanying blog.
You can also check out these exciting Educative courses:
Grokking Coding Interview Patterns in C++
With thousands of potential questions to account for, preparing for the coding interview can feel like an impossible challenge. Yet with a strategic approach, coding interview prep doesn’t have to take more than a few weeks. Stop drilling endless sets of practice problems, and prepare more efficiently by learning coding interview patterns. This course teaches you the underlying patterns behind common coding interview questions. By learning these essential patterns, you will be able to unpack and answer any problem the right way — just by assessing the problem statement. This approach was created by FAANG hiring managers to help you prepare for the typical rounds of interviews at major tech companies like Apple, Google, Meta, Microsoft, and Amazon. Before long, you will have the skills you need to unlock even the most challenging questions, grok the coding interview, and level up your career with confidence. This course is also available in JavaScript, Java, Python, C# and Go — with more coming soon!
Visual Introduction To Algorithms
Learn introductory computer science algorithms, including searching, sorting, recursion, and graph theory through a combination of articles, visualizations, quizzes, and coding challenges. Implement Challenges in Java, Python, C++ or Javascript.
Beginner to Advanced Computing and Logic Building
This course focuses on building logic to solve simple to advanced coding problems. You will learn advanced computational techniques to solve real-world problems. The solutions for most problems are curated in a way that each solution is followed by a more efficient one, enabling you to devise the most efficient algorithm from the start. The course starts with the fundamentals of variables, loops, and arrays, and progresses to more advanced concepts such as creating games like Gomoku, Word Search, and Game of Life using the divide and conquer approach. The course also includes a built-in debugger to help you understand the code by setting breakpoints and analyzing variable values. Concepts will be demonstrated via animations and illustrations to engage your interest and give you hands-on experience in building interactive games. By the end of the course, you will be well-prepared to tackle coding challenges commonly found in FAANG interviews.
Free Resources