Open In App

Longest Common Substring (Space optimized DP solution)

Last Updated : 29 Nov, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

Given two strings ‘s1‘ and ‘s2‘, find the length of the longest common substring

Example: 

Input: s1 = “GeeksforGeeks”, s2 = “GeeksQuiz” 
Output : 5 
Explanation:
The longest common substring is “Geeks” and is of length 5.

Input: s1 = “abcdxyz”, s2 = “xyzabcd” 
Output : 4
Explanation:
The longest common substring is “abcd” and is of length 4.

Input: s1 = “abc”, s2 = “” 
Output : 0.

Approach:

We have discussed a Dynamic programming based solution for the Longest common substring. The auxiliary space used by the solution is O(m*n), where m and n are lengths of strings s1 and s2. The space used by the solution can be reduced to O(2*n). 

Suppose we are at position dp[i][j]. Now if s1[i-1] == s2[j-1], then we add the value of dp[i-1][j-1] to our result. That is we add value from previous row and value for all other rows below the previous row are never used. So, at a time we are using only two consecutive rows. This observation can be used to reduce the space required to find length of longest common substring. 
Instead of creating a matrix of size m*n, we create a matrix of size 2*n. A variable currRow is used to represent that either row 0 or row 1 of this matrix is currently used to find length. Initially row 0 is used as current row for the case when length of string s1 is zero. At the end of each iteration, current row is made previous row and previous row is made new current row

C++
// C++ program to find 
// Longest Common Substring 
#include <bits/stdc++.h>
using namespace std;

// Function to find longest common substring.
int longestCommonSubstr(string& s1, string& s2) {
    
    // Find length of both strings.
    int m = s1.length();
    int n = s2.length();

    // Variable to store length of longest
    // common substring.
    int result = 0;

    // Matrix to store result of two
    // consecutive rows at a time.
    int dp[2][n];

    // Variable to represent which row of
    // matrix is current row.
    int currRow = 0;

    // For a particular value of i and j,
    // dp[currRow][j] stores length of longest
    // common substring in string X[0..i] and Y[0..j].
    for (int i = 0; i <= m; i++) {
        for (int j = 0; j <= n; j++) {
            if (i == 0 || j == 0) {
                dp[currRow][j] = 0;
            }
            else if (s1[i - 1] == s2[j - 1]) {
                dp[currRow][j] = dp[1 - currRow][j - 1] + 1;
                result = max(result, dp[currRow][j]);
            }
            else {
                dp[currRow][j] = 0;
            }
        }

        // Make current row as previous row and previous
        // row as new current row.
        currRow = 1 - currRow;
    }

    return result;
}

int main() {
    string s1 = "GeeksforGeeks";
    string s2 = "GeeksQuiz";

    cout << longestCommonSubstr(s1, s2);
    return 0;
}
Java
// Java program to find
// Longest Common Substring
import java.util.*;

class GfG {

    // Function to find longest common substring.
    static int longestCommonSubstr(String s1, String s2) {
        
        // Find length of both strings.
        int m = s1.length();
        int n = s2.length();

        // Variable to store length of longest
        // common substring.
        int result = 0;

        // Matrix to store result of two
        // consecutive rows at a time.
        int[][] dp = new int[2][n + 1];

        // Variable to represent which row of
        // matrix is current row.
        int currRow = 0;

        // For a particular value of i and j,
        // dp[currRow][j] stores length of longest
        // common substring in string X[0..i] and Y[0..j].
        for (int i = 0; i <= m; i++) {
            for (int j = 0; j <= n; j++) {
                if (i == 0 || j == 0) {
                    dp[currRow][j] = 0;
                } else if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                    dp[currRow][j] = dp[1 - currRow][j - 1] + 1;
                    result = Math.max(result, dp[currRow][j]);
                } else {
                    dp[currRow][j] = 0;
                }
            }

            // Make current row as previous row and previous
            // row as new current row.
            currRow = 1 - currRow;
        }

        return result;
    }

    public static void main(String[] args) {
        String s1 = "GeeksforGeeks";
        String s2 = "GeeksQuiz";

        System.out.println(longestCommonSubstr(s1, s2));
    }
}
Python
# Python program to find 
# Longest Common Substring

# Function to find longest common substring.
def longestCommonSubstr(s1, s2):
    
    # Find length of both strings.
    m = len(s1)
    n = len(s2)

    # Variable to store length of longest
    # common substring.
    result = 0

    # Matrix to store result of two
    # consecutive rows at a time.
    dp = [[0] * (n + 1) for _ in range(2)]

    # Variable to represent which row of
    # matrix is current row.
    currRow = 0

    # For a particular value of i and j,
    # dp[currRow][j] stores length of longest
    # common substring in string X[0..i] and Y[0..j].
    for i in range(m + 1):
        for j in range(n + 1):
            if i == 0 or j == 0:
                dp[currRow][j] = 0
            elif s1[i - 1] == s2[j - 1]:
                dp[currRow][j] = dp[1 - currRow][j - 1] + 1
                result = max(result, dp[currRow][j])
            else:
                dp[currRow][j] = 0

        # Make current row as previous row and previous
        # row as new current row.
        currRow = 1 - currRow

    return result

if __name__ == "__main__":
    s1 = "GeeksforGeeks"
    s2 = "GeeksQuiz"

    print(longestCommonSubstr(s1, s2))
C#
// C# program to find
// Longest Common Substring
using System;

class GfG {

    // Function to find longest common substring.
    static int longestCommonSubstr(string s1, string s2) {
        
        // Find length of both strings.
        int m = s1.Length;
        int n = s2.Length;

        // Variable to store length of longest
        // common substring.
        int result = 0;

        // Matrix to store result of two
        // consecutive rows at a time.
        int[,] dp = new int[2, n + 1];

        // Variable to represent which row of
        // matrix is current row.
        int currRow = 0;

        // For a particular value of i and j,
        // dp[currRow][j] stores length of longest
        // common substring in string X[0..i] and Y[0..j].
        for (int i = 0; i <= m; i++) {
            for (int j = 0; j <= n; j++) {
                if (i == 0 || j == 0) {
                    dp[currRow, j] = 0;
                } else if (s1[i - 1] == s2[j - 1]) {
                    dp[currRow, j] = dp[1 - currRow, j - 1] + 1;
                    result = Math.Max(result, dp[currRow, j]);
                } else {
                    dp[currRow, j] = 0;
                }
            }

            // Make current row as previous row and previous
            // row as new current row.
            currRow = 1 - currRow;
        }

        return result;
    }

    static void Main(string[] args) {
        string s1 = "GeeksforGeeks";
        string s2 = "GeeksQuiz";

        Console.WriteLine(longestCommonSubstr(s1, s2));
    }
}
JavaScript
// JavaScript program to find
// Longest Common Substring
// Function to find longest common substring.
function longestCommonSubstr(s1, s2) {
    
    // Find length of both strings.
    let m = s1.length;
    let n = s2.length;

    // Variable to store length of longest
    // common substring.
    let result = 0;

    // Matrix to store result of two
    // consecutive rows at a time.
    let dp = Array.from({ length: 2 }, () => Array(n + 1).fill(0));

    // Variable to represent which row of
    // matrix is current row.
    let currRow = 0;

    // For a particular value of i and j,
    // dp[currRow][j] stores length of longest
    // common substring in string X[0..i] and Y[0..j].
    for (let i = 0; i <= m; i++) {
        for (let j = 0; j <= n; j++) {
            if (i === 0 || j === 0) {
                dp[currRow][j] = 0;
            } else if (s1[i - 1] === s2[j - 1]) {
                dp[currRow][j] = dp[1 - currRow][j - 1] + 1;
                result = Math.max(result, dp[currRow][j]);
            } else {
                dp[currRow][j] = 0;
            }
        }

        // Make current row as previous row and previous
        // row as new current row.
        currRow = 1 - currRow;
    }

    return result;
}

let s1 = "GeeksforGeeks";
let s2 = "GeeksQuiz";

console.log(longestCommonSubstr(s1, s2));

Output
5

Time Complexity: O(m*n), where m is the length of string s1 and n is the length of string s2
Auxiliary Space: O(2*n), since we only need to keep track of two rows at any given time



Next Article

Similar Reads