重复删除子字符串后查找剩余字符串
Posted
技术标签:
【中文标题】重复删除子字符串后查找剩余字符串【英文标题】:Find remaining string after deleting a substring repeately 【发布时间】:2017-03-15 18:47:49 【问题描述】:让 S 和 T 被赋予字符串。然后我们在 S 中第一次出现 T 时从 S 中删除 T,并将 S 的剩余字符串称为 S1。同样,我们在 S1 中第一次出现 T 时从 S1 中删除 T,并将 S1 的剩余字符串称为 S2。重复这样做,直到在 Sk 中没有子字符串 T。
请注意,在删除 T 之后,我们可能在 S 中有一个子字符串 T。S 的剩余字符串是什么? (如果 S 为空也可以。)
约束:
1 1例如,S = "aaabbababbabab",T = "abba"。剩下的字符串是“ab”。
我正在考虑使用 KMP 在 T 上添加前缀。然后当我们在 S 中找到字符串 T 时,我们必须将索引 i 和 j(i 代表 S,j 代表 T)更改为新位置。但是,我不确定 j(可能还有 i)应该是什么?字符串可能有很多片段。
我的方法正确吗?如果是这样,您能否给我详细的步骤,尤其是 j 的新值是多少?我坚持 j 的值。我不知道找到匹配项后应该将 j 分配给什么。这是我无法弄清楚的算法的一部分。
这是我未完成的代码。
std::vector<int> make_prefix(std::string &t)
std::vector<int> prefix(t.length());
prefix[0] = 0;
for (int i = 1, j = 0; i < t.length(); )
if (t[i] == t[j])
prefix[i] = j + 1;
++i; ++j;
else if (j > 0)
j = prefix[j - 1];
else
prefix[i++] = 0;
return prefix;
std::string repeatRemoving(std::string s, std::string t)
std::vector<int> prefix = make_prefix(t);
for (int i = 0, j = 0; i < s.length(); )
if (s[i] == t[j])
++i;
++j;
else if (j > 0)
j = prefix[j - 1];
else
++i;
if (j == (int)t.length())
// What should go here after finding a match?
// How can I adjust the values of i and j?
// How can I mark the deleted characters in s?
return s;
非常感谢。
【问题讨论】:
就像回顾 KMP 后的仓促猜测一样,我认为关键是记住之前部分匹配的开始和长度,直到可以通过找到不属于任何正在进行的匹配的字符来消除它们. 你不能使用regex_replace()
删除所有这些吗?
它们可能重叠,S = "abababccc", T="abc" -> "ababcc",一次替换不正确
@KennyOstrom 正是我的想法。但是,我在实施时遇到了麻烦。它似乎比我想象的要复杂。 T 可以分成许多部分。
@Barmar 正如 Kenny Ostrom 所说,删除 T 后可能会形成一个新字符串 T。
【参考方案1】:
我找到了代码。我还需要 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(n m)
。
这是整个代码:
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);
【讨论】:
以上是关于重复删除子字符串后查找剩余字符串的主要内容,如果未能解决你的问题,请参考以下文章