We need to build the shortest possible string that contains both str1 and str2 as subsequences. The task is to merge the two strings while preserving the relative order of characters from each, using as few total characters as possible.
Concatenating the two strings gives a valid supersequence of length m + n, but we can do better. Characters that appear in both strings, in a consistent order, only need to appear once in the result. So the problem reduces to finding the longest common subsequence (LCS) of the two strings, then arranging the remaining characters around it.
If the LCS has length L, the shortest common supersequence has length m + n - L. Each of the L shared characters is written once instead of twice, and every non-shared character is written exactly once.
1 <= str1.length, str2.length <= 1000 → An O(m * n) DP solution fills at most 1,000,000 cells, well within limits. An exponential brute force is ruled out beyond very short inputs.Build the supersequence by merging the two strings character by character and explore every way to do it. With two pointers i and j tracking positions in str1 and str2, each step takes the next character from str1, the next character from str2, or, when those two characters match, takes one copy that advances both pointers.
When the current characters match, taking one shared copy is always at least as good as taking either separately, so there is no need to branch in that case. When they differ, we try both options and keep whichever recursion returns the shorter string. Exploring every branch this way guarantees we find a shortest supersequence, but the work grows exponentially.
i and j, starting at 0, to track positions in str1 and str2.i has reached the end of str1, append the rest of str2 and return.j has reached the end of str2, append the rest of str1 and return.str1[i] == str2[j], take that character once and recurse with i+1, j+1.str1[i] and recurse with i+1, j, or take str2[j] and recurse with i, j+1. Return whichever gives the shorter result.i=0, j=0.Loading animation...
This becomes too slow once the strings exceed about 15 characters, because the same subproblem (i, j) is recomputed many times across different branches. The next approach removes that redundancy with dynamic programming, building the answer from a table instead of re-deriving it.
The shortest common supersequence is built directly from the Longest Common Subsequence (LCS). A character that appears in the LCS only needs to appear once in the supersequence, because that single copy satisfies both str1 and str2 at the same time. Every other character appears once on its own. That makes the length m + n - LCS_length.
We need the actual string, not just its length. Build the standard LCS DP table, then trace back through it to construct the supersequence one character at a time. When the two current characters match (a diagonal move in the table), include that character once. When they differ, follow the direction that the DP table grew from, up or left, and include the corresponding character.
At a mismatch, dp[i][j] was set from max(dp[i-1][j], dp[i][j-1]). Moving back along that same direction follows an optimal LCS path, so the characters we skip past are exactly the non-shared ones, and the shared characters are emitted once each. Both str1 and str2 therefore remain subsequences of the result, and the result length equals m + n - LCS_length, which is the minimum possible.
The string is built back-to-front because the traceback starts at dp[m][n] and walks toward dp[0][0], so the final step reverses it.
dp[i][j] = length of LCS of str1[0..i-1] and str2[0..j-1].str1[i-1] == str2[j-1], then dp[i][j] = dp[i-1][j-1] + 1. Otherwise, dp[i][j] = max(dp[i-1][j], dp[i][j-1]).dp[m][n] to build the supersequence:str1[i-1] == str2[j-1], add this character and move diagonally (i-1, j-1).dp[i-1][j] >= dp[i][j-1], add str1[i-1] and move up (i-1, j).str2[j-1] and move left (i, j-1).Loading animation...
The next approach reaches the same answer in two separate phases: first recover the LCS string, then merge both inputs around it. The complexity is identical, but the two steps can be reasoned about independently.
This approach separates the two concerns. First find the actual LCS string, not just its length. Then use the LCS as a skeleton and merge both input strings around it. For each LCS character, include all characters from str1 and str2 that come before it (the non-shared characters), then include the LCS character once.
The result matches Approach 2. The advantage is that the LCS recovery and the merge are independent steps, each short enough to verify on its own.
Because the LCS is a subsequence of both inputs, the characters of str1 between two consecutive LCS characters do not contain any later LCS character, so emitting them before the shared character keeps str1 in order; the same holds for str2. Each shared character is written once, every other character once, giving total length m + n - LCS_length. No shorter supersequence exists, since the two strings can share at most LCS_length characters.
i for str1, j for str2, and iterate through each character c of the LCS.c:i) until str1[i] == c.j) until str2[j] == c.c once and advance i, j past it.Loading animation...