重复删除子字符串后查找剩余字符串

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);

【讨论】:

以上是关于重复删除子字符串后查找剩余字符串的主要内容,如果未能解决你的问题,请参考以下文章

PB中取字符串子串的函数是啥

数组篇在python中如何查找最长字符串子串

华为OD机试真题Java实现判断字符串子序列真题+解题思路+代码(2022&2023)

两个字符串的所有公共最长子序列

字符串子串的查找

C++编程,查找字符串子串并替换。