Back to all solutions

#943 - Find the Shortest Superstring

Problem Description

Given an array of strings words, return the smallest string that contains each string in words as a substring. If there are multiple valid strings of the smallest length, return any of them.

You may assume that no string in words is a substring of another string in words.

Solution

/**
 * @param {string[]} words
 * @return {string}
 */
var shortestSuperstring = function(words) {
  const n = words.length;
  const overlap = Array(n).fill().map(() => Array(n).fill(0));

  for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
      if (i !== j) {
        for (let k = Math.min(words[i].length, words[j].length); k > 0; k--) {
          if (words[i].slice(-k) === words[j].slice(0, k)) {
            overlap[i][j] = k;
            break;
          }
        }
      }
    }
  }

  const dp = new Array(1 << n).fill().map(() => new Array(n).fill(''));
  for (let i = 0; i < n; i++) {
    dp[1 << i][i] = words[i];
  }

  for (let mask = 1; mask < (1 << n); mask++) {
    for (let i = 0; i < n; i++) {
      if (!(mask & (1 << i))) continue;
      for (let j = 0; j < n; j++) {
        if (mask & (1 << j)) continue;
        const nextMask = mask | (1 << j);
        const candidate = dp[mask][i] + words[j].slice(overlap[i][j]);
        if (dp[nextMask][j] === '' || candidate.length < dp[nextMask][j].length) {
          dp[nextMask][j] = candidate;
        }
      }
    }
  }

  let result = dp[(1 << n) - 1][0];
  for (let i = 1; i < n; i++) {
    if (dp[(1 << n) - 1][i].length < result.length) {
      result = dp[(1 << n) - 1][i];
    }
  }

  return result;
};