Skip to main content

Shortest Common Supersequence

Problem statement​

Given two strings str1 and str2, return the shortest string that has both str1 and str2 as subsequences. If there are multiple valid strings, return any of them.

A string s is a subsequence of string t if deleting some number of characters from t (possibly 0) results in the string s.

Example 1:

Input: str1 = "abac", str2 = "cab"Output: "cabac"Explanation: str1 = "abac" is a subsequence of "cabac" because we can delete the first "c".str2 = "cab" is a subsequence of "cabac" because we can delete the last "ac".The answer provided is the shortest such string that satisfies these properties.

Example 2:

Input: str1 = "aaaaaaaa", str2 = "aaaaaaaa"Output: "aaaaaaaa"

Constraints:

  • 1 <= str1.length, str2.length <= 1000
  • str1 and str2 consist of lowercase English letters.

My solution​

/**
* @param {string} str1
* @param {string} str2
* @return {string}
*/
var shortestCommonSupersequence = function(str1, str2) {
const lcs = findLongestSubSequence(str1, str2)

if (lcs.length === 1 && lcs[0] === "") {
return set1.concat(set2)
}

let subSequence = [];

let str1Index = 0;
let str2Index = 0;
let lcsIndex = 0;
let str1OnHold = false;
let str2OnHold = false;

while (lcsIndex < lcs.length) {
if (str1Index < str1.length) {
if (!str1OnHold && lcs[lcsIndex] !== str1[str1Index]) {
subSequence.push(str1[str1Index]);
str1Index++
} else {
str1OnHold = true;
}
}

if (str2Index < str2.length) {
if (!str2OnHold && lcs[lcsIndex] !== str2[str2Index]) {
subSequence.push(str2[str2Index]);
str2Index++
} else {
str2OnHold = true;
}
}

if (str1OnHold && str2OnHold) {
subSequence.push(lcs[lcsIndex]);
lcsIndex++
str1Index++
str2Index++
str1OnHold = false;
str2OnHold = false
}
}

// console.log(str1Index, str2Index)

if (str1Index < str1.length) {
subSequence = subSequence.concat(str1.slice(str1Index))
}

if (str2Index < str2.length) {
subSequence = subSequence.concat(str2.slice(str2Index))
}

return subSequence.join("")
};

function findLongestSubSequence(str1, str2) {
const lcsMatrix = Array.from({
length: str2.length + 1
}, () => Array.from({
length: str1.length + 1
}, () => null))

for (let i = 0; i <= str1.length; i++) {
lcsMatrix[0][i] = 0
}

for (let i = 0; i <= str2.length; i++) {
lcsMatrix[i][0] = 0
}

for (let rowIdx = 1; rowIdx <= str2.length; rowIdx++) {
for (let colIdx = 1; colIdx <= str1.length; colIdx++) {
if (str1[colIdx - 1] === str2[rowIdx - 1]) {
lcsMatrix[rowIdx][colIdx] = lcsMatrix[rowIdx - 1][colIdx - 1] + 1
} else {
lcsMatrix[rowIdx][colIdx] = Math.max(
lcsMatrix[rowIdx - 1][colIdx],
lcsMatrix[rowIdx][colIdx - 1]
)
}
}
}

if (lcsMatrix[str2.length][str1.length] === 0) {
return ""
}

const longestSequence = [];
let colIdx = str1.length;
let rowIdx = str2.length;

while (colIdx > 0 || rowIdx > 0) {
if (str1[colIdx - 1] === str2[rowIdx - 1]) {
longestSequence.unshift(str1[colIdx - 1])
colIdx--
rowIdx--
} else if (lcsMatrix[rowIdx][colIdx] === lcsMatrix[rowIdx][colIdx - 1]) {
colIdx--
} else {
rowIdx--
}
}

return longestSequence.join("")
}