Longest Common Subsequence (LCS)

Problem Statement

Given two strings s1 and s2, find the length of their longest common subsequence (LCS). A subsequence is a sequence that appears in the same relative order, but not necessarily contiguous.

Example: Input: s1 = "abcde", s2 = "ace", Output: 3 ("ace")

Approach 1: Recursion

Explanation: Compare characters at current indices. If match, move both pointers. Else, take max by skipping either character.

Time Complexity: O(2m+n)

Space Complexity: O(m+n) recursion stack

function LCS(s1, s2, i, j):
    if i == len(s1) or j == len(s2): return 0
    if s1[i] == s2[j]:
        return 1 + LCS(s1, s2, i+1, j+1)
    return max(LCS(s1, s2, i+1, j), LCS(s1, s2, i, j+1))
          

Approach 2: Memoization (Top-Down DP)

Explanation: Store results of subproblems (i, j) in DP array to avoid recomputation.

Time Complexity: O(m * n)

Space Complexity: O(m * n) DP array + O(m+n) recursion stack

dp[0..m][0..n] = -1
function LCS(i, j):
    if i == m or j == n: return 0
    if dp[i][j] != -1: return dp[i][j]
    if s1[i] == s2[j]:
        dp[i][j] = 1 + LCS(i+1, j+1)
    else:
        dp[i][j] = max(LCS(i+1, j), LCS(i, j+1))
    return dp[i][j]
          

Approach 3: Tabulation (Bottom-Up DP)

Explanation: Fill a 2D DP table iteratively from the base case.

Time Complexity: O(m * n)

Space Complexity: O(m * n)

dp[0..m][0..n] = 0
for i = m-1 to 0:
    for j = n-1 to 0:
        if s1[i] == s2[j]:
            dp[i][j] = 1 + dp[i+1][j+1]
        else:
            dp[i][j] = max(dp[i+1][j], dp[i][j+1])
return dp[0][0]
          

Approach 4: Space Optimization

Explanation: Use two 1D arrays (current and next) instead of full 2D DP table.

Time Complexity: O(m * n)

Space Complexity: O(n)

prev = [0]*(n+1)
curr = [0]*(n+1)
for i = m-1 to 0:
    for j = n-1 to 0:
        if s1[i] == s2[j]:
            curr[j] = 1 + prev[j+1]
        else:
            curr[j] = max(prev[j], curr[j+1])
    prev = curr
return prev[0]
          
Flowchart