Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Python Program to Find Longest Common Substring using Dynamic Programming with Bottom-Up Approach
Finding the longest common substring using dynamic programming with a bottom-up approach involves building a solution by solving smaller subproblems first. This method uses a 2D table to store intermediate results, avoiding redundant calculations and ensuring optimal performance.
The algorithm works by comparing characters from both strings and building up the solution from the bottom of the problem space ?
Algorithm Overview
The bottom-up approach creates a 2D table where val[i][j] represents the length of the common substring ending at position i in the first string and position j in the second string. We fill this table from the bottom-right corner moving towards the top-left.
Example
def compute_lcw(string_1, string_2):
# Create a 2D table initialized with -1
val = [[-1] * (len(string_2) + 1) for _ in range(len(string_1) + 1)]
# Initialize base cases
for i in range(len(string_1) + 1):
val[i][len(string_2)] = 0
for j in range(len(string_2)):
val[len(string_1)][j] = 0
# Variables to track the longest substring
lcw_i = lcw_j = -1
lcw_len = 0
# Fill the table from bottom-right to top-left
for i in range(len(string_1) - 1, -1, -1):
for j in range(len(string_2) - 1, -1, -1):
if string_1[i] != string_2[j]:
val[i][j] = 0
else:
val[i][j] = 1 + val[i + 1][j + 1]
if lcw_len < val[i][j]:
lcw_len = val[i][j]
lcw_i = i
lcw_j = j
return lcw_len, lcw_i, lcw_j
# Test the function
string_1 = 'bull'
string_2 = 'bullied'
lcw_len, lcw_i, lcw_j = compute_lcw(string_1, string_2)
print("The longest common substring is:")
if lcw_len > 0:
print(string_1[lcw_i:lcw_i + lcw_len])
print(f"Length: {lcw_len}")
print(f"Position in string_1: {lcw_i}")
print(f"Position in string_2: {lcw_j}")
else:
print("No common substring found")
The output of the above code is ?
The longest common substring is: bull Length: 4 Position in string_1: 0 Position in string_2: 0
How It Works
The algorithm follows these key steps:
-
Table Creation: A 2D table
val[i][j]stores the length of common substring ending at positionsiandj - Base Cases: Initialize boundary conditions where one string is exhausted (length = 0)
- Character Comparison: If characters match, extend the substring length by 1 plus the diagonal value
- Tracking Maximum: Keep track of the longest substring found and its starting positions
- Bottom-Up Fill: Process from the end of both strings towards the beginning
Another Example
def compute_lcw(string_1, string_2):
val = [[-1] * (len(string_2) + 1) for _ in range(len(string_1) + 1)]
for i in range(len(string_1) + 1):
val[i][len(string_2)] = 0
for j in range(len(string_2)):
val[len(string_1)][j] = 0
lcw_i = lcw_j = -1
lcw_len = 0
for i in range(len(string_1) - 1, -1, -1):
for j in range(len(string_2) - 1, -1, -1):
if string_1[i] != string_2[j]:
val[i][j] = 0
else:
val[i][j] = 1 + val[i + 1][j + 1]
if lcw_len < val[i][j]:
lcw_len = val[i][j]
lcw_i = i
lcw_j = j
return lcw_len, lcw_i, lcw_j
# Test with different strings
string_1 = 'programming'
string_2 = 'algorithm'
lcw_len, lcw_i, lcw_j = compute_lcw(string_1, string_2)
print("Strings:", string_1, "and", string_2)
print("Longest common substring:", string_1[lcw_i:lcw_i + lcw_len] if lcw_len > 0 else "None")
print("Length:", lcw_len)
Strings: programming and algorithm Longest common substring: gram Length: 4
Time and Space Complexity
This dynamic programming approach has:
- Time Complexity: O(m × n) where m and n are the lengths of the two strings
- Space Complexity: O(m × n) for the 2D table storage
Conclusion
The bottom-up dynamic programming approach efficiently finds the longest common substring by building solutions from smaller subproblems. This method ensures optimal time complexity while maintaining clear logic for substring identification.
