Memoization and Tabulation Approaches

Memoization and tabulation approaches are two common techniques used in competitive programming to optimize the time complexity of algorithms. Both approaches aim to avoid repetitive computation by storing the results of previously solved subproblems. In this article, we will explore these approaches in the context of Competitive Programming using C++.

Memoization Approach

Memoization, also known as memoization caching, is a top-down approach that involves storing the results of expensive function calls and returning the cached value if the same inputs occur again. The idea is to avoid redundant computations by reusing already computed results.

In competitive programming, memoization is often implemented using recursive functions and a data structure such as an array or a map to store the calculated results. The recursive function checks if the result for a given input is already computed. If so, it returns the stored value; otherwise, it performs the computation, stores the result, and returns it.

Here is a simple example of implementing memoization in C++:

#include <iostream>
#include <unordered_map>

std::unordered_map<int, int> memo;

int fib(int n) {
    if (memo.find(n) != memo.end()) {
        return memo[n];
    }

    if (n <= 1) {
        memo[n] = n;
    } else {
        memo[n] = fib(n - 1) + fib(n - 2);
    }

    return memo[n];
}

int main() {
    int n = 10;
    std::cout << "Fibonacci of " << n << " : " << fib(n) << std::endl;
    return 0;
}

In this example, we use memoization to compute the nth Fibonacci number. The memo map stores the computed Fibonacci values. The fib function checks if the result for a given input n is already calculated in the memo map. If not, it recursively computes the Fibonacci number and stores the result in the memo map.

Tabulation Approach

Tabulation, also known as tabularization or bottom-up dynamic programming, is an iterative approach to solving dynamic programming problems. It involves filling up a table or an array to store the results of subproblems and building up to the final solution.

In competitive programming, the tabulation approach is often used when the problem exhibits optimal substructure and overlapping subproblems. It eliminates the need for recursive function calls and the associated overhead.

Here is a simple example of implementing tabulation in C++:

#include <iostream>
#include <vector>

int fib(int n) {
    std::vector<int> dp(n + 1);

    dp[0] = 0;
    dp[1] = 1;

    for (int i = 2; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }

    return dp[n];
}

int main() {
    int n = 10;
    std::cout << "Fibonacci of " << n << " : " << fib(n) << std::endl;
    return 0;
}

In this example, we use tabulation to compute the nth Fibonacci number. The dp vector serves as a table to store the Fibonacci values for all smaller subproblems. The loop iteratively fills up the table from the base cases (dp[0] and dp[1]) to the final solution (dp[n]).

Conclusion

Memoization and tabulation approaches are powerful techniques used in competitive programming to optimize time complexity. While memoization is a top-down approach that uses recursive functions and caching, tabulation is a bottom-up approach that uses iterative loops and tables. Both approaches help avoid redundant computations, leading to improved performance. By understanding these techniques, you can solve complex problems more efficiently in competitive programming using C++.


noob to master © copyleft