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”
Note:
1 <= A.length <= 12
1 <= A[i].length <= 20
给定一个字符串组,找出一个最小长度的串,要求字符串组中所有的字符串都是这个串的子串。
但是除了一般的DFS,因为数据量小,是可以存储所有情况的,因此也可以选择DP解决。
定义DP[i][j]:在包含序列 i 的情况下,以第 j 个字符串结尾,最小长度的串。
其中 i 表示一二进制码,该二进制码的第 k 位若为 1 ,则表示 字符串组中第 k 个字符串已为串的子串;若为 0 ,则表示 字符串组中第 k 个字符串不能在串中找到。
借助于位运算,便可以实现查找第 k 位是否已经加入到序列 i 中 以及 在序列 i 中插入第 k 位使其转移到新的序列状态。
class Solution {
private:
map<pair<int,int>,int> mapping;
public:
string shortestSuperstring(vector<string>& A) {
int N=A.size();
vector<vector<short> > dp(1<<N,vector<short>(N,0x3f3f3f3f));
vector<vector<short> > parent(1<<N,vector<short>(N,-1));
for(int i=0;i<N;i++)
dp[1<<i][i]=A[i].size();;
for(register int mark=0;mark < (1<<N);mark++){
for(register int i=0;i<N;i++){
//if i have existed in this subsequence already
if((mark>>i) & 1 > 0){//if exist
int parentMark=mark ^ (1<<i);
if(parentMark==0) //meaningless
continue;
for(int j=0;j<N;j++){
//if i have existed in this subsequence already
if((parentMark>>j) & 1 > 0){
int pos=overlap(A,j,i);
int length=A[i].size()-pos;
//salck operation
if(dp[mark][i] > dp[parentMark][j]+length){
dp[mark][i]=dp[parentMark][j]+length;
parent[parentMark][i]=j;
}
}
}
}
}
}
//find the min status
short index=0;
for(register int i=0;i<N;i++)
if(dp[(1<<N)-1][i] < dp[(1<<N)-1][index])
index=i;
stack<char> store;
for(int i=A[index].size()-1;i>=0;i--)
store.push(A[index][i]);
int num=1;
int lastIndex=index;
int nowIndex,nowMark=(1<<N)-1;
while(num<N){
nowMark=nowMark ^ (1<<lastIndex);
nowIndex=parent[nowMark][lastIndex];
if(nowIndex==-1)
cout<<"overstack"<<endl;
int pos=overlap(A,nowIndex,lastIndex);
for(int i=A[nowIndex].size()-pos-1;i>=0;i--)
store.push(A[nowIndex][i]);
lastIndex=nowIndex;
num++;
}
//get ans string
string ans;
while(!store.empty()){
ans+=store.top();
store.pop();
}
return ans;
}
int overlap(vector<string>& A,int matched,int match){ //return the first not matched element position
pair<int,int> temp=make_pair(matched,match);
if(mapping.find(temp)!=mapping.end())
return mapping[temp];
int minLen=min(A[matched].size(),A[match].size());
for(int len=minLen;len>0;len--){
int i=A[matched].size()-1;
int j=len-1;
bool sym=true;
int num=len;
while(num){
if(A[match][j]!=A[matched][i]){
sym=false;
break;
}
j--,i--;
num--;
}
if(sym)
return mapping[temp]=len;
}
return mapping[temp]=0;
}
};
Note:
-
左移 与 右移 运算优先级较低
计算时加括号提升优先级 -
在查找时,不可用 异或运算 来代替 与运算
根据上图可知,在执行 左移 操作后,并不能通过 异或运算来判断第k个字符串是否已经加入序列