Open In App

Printing Shortest Common Supersequence

Last Updated : 13 Feb, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given two strings s1 and s2, find the shortest string which has both s1 and s2 as its sub-sequences. If multiple shortest super-sequence exists, print any one of them.

Examples:

Input: s1 = "geek", s2 = "eke"
Output: geeke
Explanation: String "geeke" has both string "geek" and "eke" as subsequences.

Input: s1 = "AGGTAB", s2 = "GXTXAYB"
Output: AGXGTXAYB
Explanation: String "AGXGTXAYB" has both string "AGGTAB" and "GXTXAYB" as subsequences.

Approach:

The idea is to find the shortest common supersequence (SCS) of two strings by using a dynamic programming (DP) table to calculate the minimum length of the merged string while preserving character order. It builds the SCS by backtracking from the DP table, adding common characters when they match and choosing the smaller cost path when they don’t. Finally, the result is reversed as it’s constructed backward.

To solve the problem, we use a DP table where dp[i][j] represents the length of the shortest common supersequence (SCS) for the first i characters of s1 and the first j characters of s2.

Base Cases:

  • dp[0][j]: If s1 is empty, SCS is all characters of s2, so dp[0][j] = j.
  • dp[i][0]: If s2 is empty, SCS is all characters of s1, so dp[i][0] = i.

Filling the Table:

Case 1: If s1[i-1] == s2[j-1]:

  • When the current characters of s1 and s2 are the same, they must appear only once in the SCS. So, we add 1 to the result of the SCS for the previous characters (dp[i-1][j-1]).

Case 2: If s1[i-1] != s2[j-1]:

  • When the current characters differ, we have two choices:
  • Include the character from s1 (add 1 to dp[i-1][j]), which means the SCS considers this character of s1.
  • Include the character from s2 (add 1 to dp[i][j-1]), which means the SCS considers this character of s2. We take the minimum of these two, as we want the shortest sequence.

The following table shows steps followed by the above algorithm if we solve it in bottom-up manner using Dynamic Programming for strings X = “AGGTAB” and Y = “GXTXAYB”,

Shortest-Supersequence
SCS Example

Construct the SCS

The DP table is filled row by row, starting from dp[0][0] up to dp[m][n], where m and n are the lengths of s1 and s2. After filling the table, dp[m][n] contains the length of the shortest common supersequence.

  • Begin at the bottom-right cell (dp[m][n]), representing the SCS for the full strings s1 and s2.
  • Case 1 (Characters Match):
    • If s1[i-1] == s2[j-1], the current character is part of the SCS.
    • Add it to the result and move diagonally (i--, j--).
  • Case 2 (Characters Differ):
    • Compare dp[i-1][j] and dp[i][j-1] to find the smaller value.
    • If dp[i-1][j] < dp[i][j-1], include s1[i-1] in the result and move up (i--).
    • Otherwise, include s2[j-1] and move left (j--).
  • Handling Remaining Characters:
    • If i == 0, append the remaining characters of s2 to the result.
    • If j == 0, append the remaining characters of s1 to the result.
  • Reverse the Result:
    • Since the result is built backward, reverse it at the end to obtain the final SCS.
C++
#include <bits/stdc++.h>
using namespace std;

// Function to find and print the shortest common
// supersequence of two strings.
string shortestCommonSupersequence(string& s1, string& s2) {
    int m = s1.size(), n = s2.size();
    vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));

    // Filling the dp table
    for (int i = 0; i <= m; i++) {
        for (int j = 0; j <= n; j++) {
            if (i == 0) {
                dp[i][j] = j;
            } else if (j == 0) {
                dp[i][j] = i;
            } else if (s1[i - 1] == s2[j - 1]) {
                dp[i][j] = 1 + dp[i - 1][j - 1];
            } else {
                dp[i][j] = 1 + min(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }

    // Constructing the shortest supersequence from dp table
    int i = m, j = n;
    string result = "";
    while (i > 0 && j > 0) {
        if (s1[i - 1] == s2[j - 1]) {
            result += s1[i - 1];
            i--, j--;
        } else if (dp[i - 1][j] < dp[i][j - 1]) {
            result += s1[i - 1];
            i--;
        } else {
            result += s2[j - 1];
            j--;
        }
    }

    // Adding remaining characters
    while (i > 0) {
        result += s1[i - 1];
        i--;
    }
    while (j > 0) {
        result += s2[j - 1];
        j--;
    }

    // Reverse the result since we built it backwards
    reverse(result.begin(), result.end());
    return result;
}

int main() {

    string s1 = "AGGTAB";
    string s2 = "GXTXAYB";

    cout << shortestCommonSupersequence(s1, s2);

    return 0;
}
Java
import java.util.*;

class GfG {
    // Function to find and return the shortest common supersequence
    static String shortestCommonSupersequence(String s1, String s2) {
        int m = s1.length(), n = s2.length();
        int[][] dp = new int[m + 1][n + 1];

        // Filling the dp table
        for (int i = 0; i <= m; i++) {
            for (int j = 0; j <= n; j++) {
                if (i == 0) {
                    dp[i][j] = j;
                } else if (j == 0) {
                    dp[i][j] = i;
                } else if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                    dp[i][j] = 1 + dp[i - 1][j - 1];
                } else {
                    dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }

        // Constructing the shortest supersequence
        int i = m, j = n;
        StringBuilder result = new StringBuilder();
        while (i > 0 && j > 0) {
            if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                result.append(s1.charAt(i - 1));
                i--;
                j--;
            } else if (dp[i - 1][j] < dp[i][j - 1]) {
                result.append(s1.charAt(i - 1));
                i--;
            } else {
                result.append(s2.charAt(j - 1));
                j--;
            }
        }

        // Adding remaining characters
        while (i > 0) {
            result.append(s1.charAt(i - 1));
            i--;
        }
        while (j > 0) {
            result.append(s2.charAt(j - 1));
            j--;
        }

        return result.reverse().toString();
    }

    public static void main(String[] args) {
        String s1 = "AGGTAB";
        String s2 = "GXTXAYB";
        System.out.println(shortestCommonSupersequence(s1, s2));
    }
}
Python
def shortest_common_supersequence(s1, s2):
    m, n = len(s1), len(s2)
    dp = [[0] * (n + 1) for _ in range(m + 1)]

    # Filling the dp table
    for i in range(m + 1):
        for j in range(n + 1):
            if i == 0:
                dp[i][j] = j
            elif j == 0:
                dp[i][j] = i
            elif s1[i - 1] == s2[j - 1]:
                dp[i][j] = 1 + dp[i - 1][j - 1]
            else:
                dp[i][j] = 1 + min(dp[i - 1][j], dp[i][j - 1])

    # Constructing the shortest supersequence
    i, j = m, n
    result = []
    while i > 0 and j > 0:
        if s1[i - 1] == s2[j - 1]:
            result.append(s1[i - 1])
            i -= 1
            j -= 1
        elif dp[i - 1][j] < dp[i][j - 1]:
            result.append(s1[i - 1])
            i -= 1
        else:
            result.append(s2[j - 1])
            j -= 1

    # Adding remaining characters
    while i > 0:
        result.append(s1[i - 1])
        i -= 1
    while j > 0:
        result.append(s2[j - 1])
        j -= 1

    return "".join(result[::-1])

if __name__ == "__main__":
    s1 = "AGGTAB"
    s2 = "GXTXAYB"
    print(shortest_common_supersequence(s1, s2))
C#
using System;

class GfG {
    // Function to find and return the shortest common supersequence
    public static string ShortestCommonSupersequence(string s1, string s2) {
        int m = s1.Length, n = s2.Length;
        int[,] dp = new int[m + 1, n + 1];

        // Filling the dp table
        for (int i = 0; i <= m; i++) {
            for (int j = 0; j <= n; j++) {
                if (i == 0) {
                    dp[i, j] = j;
                } else if (j == 0) {
                    dp[i, j] = i;
                } else if (s1[i - 1] == s2[j - 1]) {
                    dp[i, j] = 1 + dp[i - 1, j - 1];
                } else {
                    dp[i, j] = 1 + Math.Min(dp[i - 1, j], dp[i, j - 1]);
                }
            }
        }

        // Constructing the shortest supersequence
        int x = m, y = n;
        string result = "";
        while (x > 0 && y > 0) {
            if (s1[x - 1] == s2[y - 1]) {
                result = s1[x - 1] + result;
                x--;
                y--;
            } else if (dp[x - 1, y] < dp[x, y - 1]) {
                result = s1[x - 1] + result;
                x--;
            } else {
                result = s2[y - 1] + result;
                y--;
            }
        }

        // Adding remaining characters
        while (x > 0) {
            result = s1[x - 1] + result;
            x--;
        }
        while (y > 0) {
            result = s2[y - 1] + result;
            y--;
        }

        return result;
    }

    public static void Main() {
        string s1 = "AGGTAB";
        string s2 = "GXTXAYB";
        Console.WriteLine(ShortestCommonSupersequence(s1, s2));
    }
}
JavaScript
function shortestCommonSupersequence(s1, s2) {
    let m = s1.length, n = s2.length;
    let dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));

    // Filling the dp table
    for (let i = 0; i <= m; i++) {
        for (let j = 0; j <= n; j++) {
            if (i === 0) {
                dp[i][j] = j;
            } else if (j === 0) {
                dp[i][j] = i;
            } else if (s1[i - 1] === s2[j - 1]) {
                dp[i][j] = 1 + dp[i - 1][j - 1];
            } else {
                dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }

    // Constructing the shortest supersequence
    let i = m, j = n, result = [];
    while (i > 0 && j > 0) {
        if (s1[i - 1] === s2[j - 1]) {
            result.push(s1[i - 1]);
            i--;
            j--;
        } else if (dp[i - 1][j] < dp[i][j - 1]) {
            result.push(s1[i - 1]);
            i--;
        } else {
            result.push(s2[j - 1]);
            j--;
        }
    }

    // Adding remaining characters
    while (i > 0) {
        result.push(s1[i - 1]);
        i--;
    }
    while (j > 0) {
        result.push(s2[j - 1]);
        j--;
    }

    return result.reverse().join("");
}

// Example usage
let s1 = "AGGTAB";
let s2 = "GXTXAYB";
console.log(shortestCommonSupersequence(s1, s2));

Output
AGGXTXAYB

Time Complexity: O(|str1|*|str2|), as we are running nested loop which is iterating |str1|*|str2| times.
Auxiliary Space: O(|str1|*|str2|), as we are using dp array of size |str1|*|str2|.



Next Article

Similar Reads