My Learning Blog

DP-1143 - 2/25/2024

use dfs with memo and dp table

One using memoization (top-down approach) and the other using dynamic programming (bottom-up approach).I prefer the DP method.

function longestCommonSubsequence(text1: string, text2: string): number {
    // A cache to remember solutions to subproblems we've already solved
    const memo = new Map<string, number>();

    // A recursive helper function to find LCS length for substrings up to indices i and j
    function dfs(i: number, j: number): number {
        // Base case: if either string is fully traversed, return 0
        if (i < 0 || j < 0) return 0;

        // Generate a unique key to identify the current state (subproblem)
        const key = `${i},${j}`;
        // If this problem was already solved, return the stored result
        if (memo.has(key)) return memo.get(key)!;

        let result = 0;
        // If characters at current positions are the same, move diagonally and add 1
        if (text1[i] === text2[j]) {
            result = dfs(i - 1, j - 1) + 1;
        } else {
            // Otherwise, try moving in either string and choose the max result
            result = Math.max(dfs(i - 1, j), dfs(i, j - 1));
        }

        // Store the result in the cache before returning
        memo.set(key, result);
        return result;
    }

    // Start the recursion from the end of both strings
    return dfs(text1.length - 1, text2.length - 1);
};


function longestCommonSubsequence(text1: string, text2: string): number {
    const m = text1.length
    const n = text2.length
    const dp = Array.from({length:m + 1}, () => Array(n + 1).fill(0))

    for(let i = 1; i <= m; i++){
        for(let j = 1; j <= n; j++){
            if(text1[i -1] === text2[j-1]){
                dp[i][j] = dp[i-1][j-1] + 1
            }else{
                dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1])
            }
        }
    }

    return dp[m][n]
};