C++ 重复删除子字符串后查找剩余字符串
设S和T为字符串。然后,当T在S中第一次出现时,我们将T从S中移除,并将剩余的S字符串称为S1。同样,我们在S1中第一次出现T时从S1中删除T,并将S1的剩余字符串称为S2。重复这样做,直到Sk中没有子串T 请注意,在删除T之后,S中可能有一个子字符串T。S的剩余字符串是什么?(如果S为空则可以。) 约束条件:C++ 重复删除子字符串后查找剩余字符串,c++,arrays,string,algorithm,search,C++,Arrays,String,Algorithm,Search,设S和T为字符串。然后,当T在S中第一次出现时,我们将T从S中移除,并将剩余的S字符串称为S1。同样,我们在S1中第一次出现T时从S1中删除T,并将S1的剩余字符串称为S2。重复这样做,直到Sk中没有子串T 请注意,在删除T之后,S中可能有一个子字符串T。S的剩余字符串是什么?(如果S为空则可以。) 约束条件: (10) j=前缀[j-1]; 其他的 前缀[i++]=0; 返回前缀; } std::string repeatRemoving(std::string s,std::string
- (10)
j=前缀[j-1];
其他的
前缀[i++]=0;
返回前缀;
}
std::string repeatRemoving(std::string s,std::string t){
std::vector prefix=make_prefix(t);
对于(int i=0,j=0;i
0) j=前缀[j-1]; 其他的 ++一,; 如果(j==(int)t.length()){ //找到匹配项后,应该到这里做什么? //如何调整I和j的值? //如何在s中标记已删除的字符? } } 返回s; }
非常感谢。我算出了密码。我还需要2个阵列:
:存储prev
索引在i
上的先前位置。最初S
。当我们在prev[i]=prev[i-1]
位置找到匹配项时,我们将i+length(T)
(即我们将prev[i+length(T)+1]=i-1
指向一个新位置prev
跳过整个字符串i
)T
:在jv
上的每个S
位置存储i
的值j
中的所有S
之后,我们使用T
重建剩余的字符串。总体复杂度为prev
以下是全部代码:O(nm)
重复删除后剩下的字符串(std::string s,std::string t){ std::vector prefix=make_prefix(t); s+=“#”; std::vector prev(s.length()); std::vector jv(s.length()); 对于(int i=0;istd::string remaining_after_delete_repeatedly(std::string s, std::string t) { std::vector<int> prefix = make_prefix(t); s += "#"; std::vector<int> prev(s.length()); std::vector<int> jv(s.length()); for (int i = 0; i < s.length(); prev[i] = i - 1, ++i); for (int i = 0, j = 0; i < s.length(); ) { if (s[i] == t[j]) { jv[i] = j; ++i; ++j; } else if (j > 0) j = prefix[j - 1]; else jv[i++] = 0; if (j == (int)t.length()) { int u = i - 1; for (int k = 0; k < t.length(); ++k) u = prev[u]; prev[i] = u; j = u < 0 ? 0 : jv[u] + 1; } } std::string answer(1, s.back()); for (int i = prev[s.length() - 1]; i > -1; i = prev[i]) answer += s[i]; std::reverse(answer.begin(), answer.end()); return answer.substr(0, answer.length() - 1); }
0) j=前缀[j-1]; 其他的 jv[i++]=0; 如果(j==(int)t.length()){ int u=i-1; 对于(int k=0;k -1;i=prev[i]) 答案+=s[i]; std::reverse(answer.begin(),answer.end()); 返回answer.substr(0,answer.length()-1); }
就像在查看KMP后的仓促猜测一样,我认为关键在于记住以前部分匹配的开始和长度,直到找到一个不属于任何正在进行的匹配的字符来消除它们。您不能使用
删除所有这些字符吗?它们可能重叠,S=“abababacc”,t=“abc”->“abababcc”,不正确,一次通过replace@KennyOstrom正是我所想的。然而,我很难实现这一点。这似乎比我想象的要复杂。“T可能会分裂成许多碎片。@巴尔马正如肯尼·奥斯特罗姆所说,在移除T之后,可能会形成一个新的字符串T。regex_replace()
std::string remaining_after_delete_repeatedly(std::string s, std::string t) { std::vector<int> prefix = make_prefix(t); s += "#"; std::vector<int> prev(s.length()); std::vector<int> jv(s.length()); for (int i = 0; i < s.length(); prev[i] = i - 1, ++i); for (int i = 0, j = 0; i < s.length(); ) { if (s[i] == t[j]) { jv[i] = j; ++i; ++j; } else if (j > 0) j = prefix[j - 1]; else jv[i++] = 0; if (j == (int)t.length()) { int u = i - 1; for (int k = 0; k < t.length(); ++k) u = prev[u]; prev[i] = u; j = u < 0 ? 0 : jv[u] + 1; } } std::string answer(1, s.back()); for (int i = prev[s.length() - 1]; i > -1; i = prev[i]) answer += s[i]; std::reverse(answer.begin(), answer.end()); return answer.substr(0, answer.length() - 1); }