Search code examples
pythonalgorithmlongest-substring

whats the problem with the given solution to the LCS problem?


I have a recursive solution to the longest common subsequence problem of two strings given below:

def LCS(i, j, lcs): # i , j are the position of character in X and Y respectively which are being compared
                    # lcs is the string storing the current longest common subsequence
    print(i, j, lcs)
    if i == 0 or j == 0: # basic case
        return lcs

    if X[i - 1] == Y[j - 1]:  # increment lcs 
        lcs = X[i - 1] + lcs
        return lcs

  # else check for LCS(i-1,j) and LCS(i,j-1)

    lcs_copy = str(lcs)
    lcs1 = LCS(i - 1, j, lcs_copy)
    x = len(lcs1)
    lcs_copy = str(lcs)
    lcs2 = LCS(i, j - 1, lcs_copy)
    y = len(lcs2)

    if x > y:
        lcs = lcs1
    else:
        lcs = lcs2
    return lcs


X = 'abcbddab'
Y = 'bdcaba'
lcs = ''
lcs = LCS(8, 6, lcs)
print(lcs)

but it doesn't give the desired result. any suggestion where might be the issue?


Solution

  • Keeping most of OP code we have two corrections:

    1. The base case needs recursive call
    2. No need to copy string lcs before calling recursively

    Code

    def LCS(i, j, lcs):
      """i , j are the position of character in X and Y respectively which are being compared
          lcs is the string storing the current longest common substring"""
    
      # Base Cases
      if i == 0 or j == 0: # basic case
          return lcs
    
      if X[i - 1] == Y[j - 1]: 
          # add current string to longest of
          # precusor strings
          return LCS(i-1, j-1, X[i - 1] + lcs)
    
      # else: check for LCS(i-1,j) and LCS(i,j-1)
      lcs1 = LCS(i - 1, j, lcs)
      lcs2 = LCS(i, j - 1, lcs)
    
      if len(lcs1) > len(lcs2):
          return lcs1
      else:
          return lcs2
    

    Test

    X = 'abcbddab'
    Y = 'bdcaba'
    lcs = ''
    lcs = LCS(8, 6, lcs)
    print(lcs)  # Output: bdab
    

    Rewriting function

    1. The function should be self-contained (no need to refer to global X, Y)
    2. Use PEP 8 function naming convention

    Refactored Code

    def lcs(str1, str2):
      """input strings str1, str2"""
    
      # Base Case
      if not str1 or not str2: # one is empty
          return ""
    
      if str1[-1] == str2[-1]: 
          # add current string to longest of
          # precusor strings
          return lcs(str1[:-1], str2[:-1]) + str1[-1]
    
      # else check for LCS(i-1,j) and LCS(i,j-1)
      return max(lcs(str1[:-1], str2), lcs(str1, str2[:-1]), key = len)
    
    print(lcs('abcbddab', 'bdcaba'))
    # Output: bcba (different longest sequence but same length)