的數量。
首先在子樹中插入你的子串。然後定義dp的狀態是一些字符串,遍歷該字符串並將每個i(對於i = 0 .. s.length())作爲某個子字符串的開始。讓j = i並增加j,只要你在trie中有一個後綴(這肯定會讓你至少有一個子字符串,如果你在一些子字符串之間有共同的後綴,比如「abce」和「abdd」 ),每遇到一個子字符串的結尾,就解決新的子問題,並找到所有子字符串縮減之間的最小值。
這是我的代碼。不要擔心代碼的長度。只要閱讀解析函數並忘記路徑,我將它包括在內以打印形成的字符串。
struct node{
node* c[26];
bool str_end;
node(){
for(int i= 0;i<26;i++){
c[i]=NULL;
}
str_end= false;
}
};
class Trie{
public:
node* root;
Trie(){
root = new node();
}
~Trie(){
delete root;
}
};
class Solution{
public:
typedef pair<int,int>ii;
string get_str(string& s,map<string,ii>&path){
if(!path.count(s)){
return s;
}
int i= path[s].first;
int j= path[s].second;
string new_str =(s.substr(0,i)+s.substr(j+1));
return get_str(new_str,path);
}
int solve(string& s,Trie* &t, map<string,int>&dp,map<string,ii>&path){
if(dp.count(s)){
return dp[s];
}
int mn= (int)s.length();
for(int i =0;i<s.length();i++){
string left = s.substr(0,i);
node* cur = t->root->c[s[i]-97];
int j=i;
while(j<s.length()&&cur!=NULL){
if(cur->str_end){
string new_str =left+s.substr(j+1);
int ret= solve(new_str,t,dp,path);
if(ret<mn){
path[s]={i,j};
}
}
cur = cur->c[s[++j]-97];
}
}
return dp[s]=mn;
}
string removeSubstrings(vector<string>& substrs, string s){
map<string,ii>path;
map<string,int>dp;
Trie*t = new Trie();
for(int i =0;i<substrs.size();i++){
node* cur = t->root;
for(int j=0;j<substrs[i].length();j++){
if(cur->c[substrs[i][j]-97]==NULL){
cur->c[substrs[i][j]-97]= new node();
}
cur = cur->c[substrs[i][j]-97];
if(j==substrs[i].length()-1){
cur->str_end= true;
}
}
}
solve(s,t,dp,path);
return get_str(s, path);
}
};
int main(){
vector<string>substrs;
substrs.push_back("ab");
substrs.push_back("cd");
Solution s;
cout << s.removeSubstrings(substrs,"ccdaabcdbb")<<endl;
return 0;
}
問題的規模是什麼(字符串的長度,子字符串的數量)? BFS可以解決這個問題,但是對於大型字符串可能不夠有效 – amit
@amit我猜BFS會花費O(| S |^2 * | SET |) – piotrekg2