Find the Shortest Superstring - Complete Solution Guide
Find the Shortest Superstring is LeetCode problem 943, a Hard level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
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 . Example 1: Input: words = ["alex","loves","leetcode"] Output: "alexlovesleetcode" Explanation: All permutations of "alex","loves","leetcode" would also be accepted. Example 2: Input: words = ["catg","ctaagt","gcta","ttca","
Detailed Explanation
The problem requires finding the shortest possible string (superstring) that contains all the strings in a given array of strings as substrings. The input is an array of strings called `words`. The output is the shortest superstring containing all input strings. We are guaranteed that no string in `words` is a substring of another string in `words`. If there are multiple shortest superstrings, any one of them can be returned. The number of words is limited to 12, and each word is at most 20 characters long.
Solution Approach
The solution uses dynamic programming with bitmasking to find the optimal order of strings. It first computes the maximum overlap between each pair of strings `words[i]` and `words[j]`. Then, it uses a DP table `dp[mask][i]` to store the maximum overlap achieved by including the strings represented by the bitmask `mask` and ending with the string `words[i]`. The `parent[mask][i]` table stores the previous string in the optimal path. Finally, it reconstructs the optimal path and concatenates the strings, considering overlaps to create the shortest superstring.
Step-by-Step Algorithm
- Step 1: Calculate the overlaps between all pairs of words. The `overlaps[i][j]` stores the length of the longest suffix of `words[i]` that is also a prefix of `words[j]`.
- Step 2: Initialize the DP table `dp` and `parent` table. `dp[mask][i]` stores the maximum overlap obtained using the strings represented by the mask `mask` and ending with word `i`. `parent[mask][i]` stores the index of the word preceding word `i` in the shortest superstring formed by words in mask `mask` ending with word `i`.
- Step 3: Iterate through all possible masks from 1 to 2^n - 1. For each mask, iterate through all words `i` included in the mask. Then, iterate through all words `j` in the previous mask (`mask` XOR `1 << i`). Update `dp[mask][i]` and `parent[mask][i]` if a better overlap is found by appending word `i` after word `j`.
- Step 4: Find the maximum overlap in the final mask `(1 << n) - 1`. This gives the maximum overlap across all permutations.
- Step 5: Backtrack through the `parent` table to reconstruct the optimal order of strings in the superstring.
- Step 6: Construct the shortest superstring by concatenating the words in the optimal order, considering the overlaps between adjacent words.
Key Insights
- Insight 1: Dynamic programming with bitmasking is suitable because the number of words is small (<= 12), allowing us to represent the set of used words with a bitmask.
- Insight 2: Calculating the overlap between each pair of words beforehand avoids redundant computations within the dynamic programming loop.
- Insight 3: The problem can be viewed as finding the optimal order of the strings in `words` to minimize the length of their concatenation, considering overlaps.
Complexity Analysis
Time Complexity: O(n^2 * 2^n)
Space Complexity: O(n * 2^n)
Topics
This problem involves: Array, String, Dynamic Programming, Bit Manipulation, Bitmask.
Companies
Asked at: DE Shaw.