In [1]:
def traceLcs(D, x, y):
    ''' Backtrace for LCS; returns LCS as string. '''
    i, j = len(x), len(y) # start in lower-right
    st = []
    while i > 0 and j > 0:
        # get the three contributions
        diag, vert, horz = 0, 0, 0
        if i > 0 and j > 0:
            delt = -1 if x[i-1] == y[j-1] else 1
            diag = D[i-1, j-1] + delt
        if i > 0: vert = D[i-1, j]
        if j > 0: horz = D[i, j-1]
        if diag <= vert and diag <= horz:
            # diagonal is best, thus, this char is part of LCS
            st.append(x[i-1])
            i -= 1; j -= 1 # move up and left
        elif vert <= horz: i -= 1 # vertical is best; move up
        else: j -= 1 # horizontal is best; move left
    # reverse it, then return string-ized LCS
    return (''.join(st))[::-1]

import numpy
def lcsDp(x, y):
    ''' Return LCS of x and y.  Uses bottom-up dynamic programming
        approach. '''
    D = numpy.zeros((len(x)+1, len(y)+1), dtype=int)
    for i in range(1, len(x)+1):
        for j in range(1, len(y)+1):
            delt = -1 if x[i-1] == y[j-1] else 1
            D[i, j] = min(D[i-1, j-1] + delt, D[i-1, j], D[i, j-1])
    return traceLcs(D, x, y), D
In [2]:
lcs, D = lcsDp('ATCTGAT', 'TGCATA') # example from Jones & Pevzner 6.5
lcs
Out[2]:
'TCTA'
In [3]:
D
Out[3]:
array([[ 0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0, -1, -1, -1],
       [ 0, -1, -1, -1, -1, -2, -2],
       [ 0, -1, -1, -2, -2, -2, -2],
       [ 0, -1, -1, -2, -2, -3, -3],
       [ 0, -1, -2, -2, -2, -3, -3],
       [ 0, -1, -2, -2, -3, -3, -4],
       [ 0, -1, -2, -2, -3, -4, -4]])