Longest common subsequence

Longest Common Subsequence is the problem of finding the longest common subsequence of two sequences of items. It utilizes dynamic programming.

Overview
The problem is usually defined as:

Given two sequence of items, find the longest common subsequence between them. A subsequence is a sequence that appears in the same relative order, but not necessarily contiguous. For example, in the string abcdefg, "abc", "abg", "bdf", "aeg" are all subsequences.

A naive exponential algorithm is to notice that there are only $$O(2^n)$$ different substrings, so we would take the shorter string, and test it against the other string greedily.

Dynamic Programming
We can try to solve the problem recursively. Given two strings x and y of length n and m, respectively, we can try to solve the subproblem of finding the longest common subsequence by taking the best of the three possible cases:


 * 1) Take the longest common subsequence of the string $$x_{1...n-1}$$, and $$y_{1...m}$$
 * 2) Take the longest common subsequence of the string $$x_{1...n}$$, and $$y_{1...m-1}$$
 * 3) Take the longest common subsequence of the string $$x_{1...n-1}$$, and $$y_{1...m-1}$$, appending the last character if $$x_{n}$$ is the same as $$y_{m}$$

It is easy to construct a recursive solution for this:

func lcs( a, b ) if ( length( a ) = 0 or length( b ) = 0 ) return "" best = lcs( a[ 1, n ], b[ 1, m - 1 ] ) if ( length( best ) < length( lcs( a[ 1, n - 1 ], b[ 1, m ] ) ) ) best = lcs( a[ 1, n - 1 ], b[ 1, m ] ) if ( a[ n ] = b[ m ] and length( best ) < length( lcs( a[ 1, n - 1 ], b[ 1, m - 1 ] ) + 1 )     best = lcs( a[ 1, n - 1 ], b[ 1, m - 1 ] ) + a[ n ]   if ( length( best ) < length( lcs( a[ 1, n - 1 ], b[ 1, m - 1 ] ) ) best = lcs( a[ 1, n - 1 ], b[ 1, m - 1 ] ) return best

Obviously, this is still not very efficient. But, because the subproblems are repeated, we can use memoization!