Given an array A of strings, find any smallest string that contains each string in A as a substring.
We may assume that no string in A is substring of another string in A.
Example 1:
Input: [“alex”,“loves”,“leetcode”]
Output: “alexlovesleetcode”
Explanation: All permutations of “alex”,“loves”,“leetcode” would also be accepted.
Example 2:
Input: [“catg”,“ctaagt”,“gcta”,“ttca”,“atgcatc”]
Output: “gctaagttcatgcatc”
class Solution {
public:
string shortestSuperstring(vector<string>& A) {
int n = A.size();
// cal overlap between ith and jth in A
vector<vector<int>> overlap(n,vector<int>(n,0));
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(i!=j){
for(int k=min(A[i].size(),A[j].size());k>0;k--){
if(A[i].substr(A[i].size()-k) == A[j].substr(0,k)){
overlap[i][j] = k;
break;
}
}
}
}
}
// dp i 表示第i个 initial val for dp
vector<vector<string>> dp((1<<n),vector<string>(n));
for(int i=0; i<n; ++i) dp[1<<i][i] += A[i];
// fill the dp
for(int mask=1;mask<(1<<n);mask++){
for(int j=0;j<n;j++){
if((mask&(1<<j))!=0){
for(int i=0;i<n;i++)if(i!=j && (mask&(1<<i))!=0){
string tmp = dp[mask^(1<<j)][i]+A[j].substr(overlap[i][j]);
if(dp[mask][j].empty() || tmp.size()< dp[mask][j].size()){
dp[mask][j] = tmp;
}
}
}
}
}
// result
int last = (1<<n)-1;
string res = dp[last][0];
for(int i=1;i<n;i++){
if(res.size() > dp[last][i].size()){
res = dp[last][i];
}
}
return res;
}
};
如果用brute force复杂度n! 用dp可以降到n^2 * 2^n. dp[i][j] 表示,以A[j]为最后一个string。I是mask用来表示A[0:n-1]有哪些string包含在set内。mask=110, 表示A里面有三个string,第一个和第二个被包含的情况。
一些mask的操作包括: mask&(1<<i))!=0 用来判断 A[I] 是否包含在set内。
mask^(1<<j) 在A[j]为1的情况下,表示从set中抹掉j。
递推:
dp[mask][j] = dp[mask^(1<<j)][i]+A[j].substr(overlap[i][j])。
mask常用于 排列组合问题。