c++ 在串构建中可靠地检测子串模式

8iwquhpp  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(89)

我正在尝试做一个编程任务,但我未能满足性能要求。这里是它的完整描述:
语言模型将一个n字母单词S和一个参数k(1 ≤ k < n的整数)作为输入,然后根据下面指定的规则生成该单词的延续。
假设我们已经有一个单词S′,它是S的某些字母的扩展,添加一个新字母的工作原理如下(另见下面的例子):我们考虑单词S′k字母后缀R,并查看单词S′R之前出现的所有情况(作为连续的子字符串)。然后,对于字母表中的每个字母,我们计算它在单词S′中直接出现在R之后的次数。令l是出现频率最高的字母。关系被解决为有利于字母表中出现较早的字母,并且如果R没有出现在单词S′中的任何其他地方,则我们假设l= 'a'。最后,我们在单词S′的末尾加上字母l来扩展它。
例如,假设S=“abaaabababa”,k= 3。我们有S′=SR= aba,R出现得更早,下一个字母是abaa,abab,abab。最常见的字母是b,所以我们将b附加到S′。现在S′=“abaaababababab”,R= bab,而R出现得更早,下一个字母是baba,baba,所以我们把'a'附加到S′
输入:输入的第一行包含四个整数nkaB(2 ≤n≤ 10^6,1 ≤k<nn<a<B< 10^18,B+ 1 −a≤ 10^6)。输入的第二行包含一个n字母字符串,该字符串由两个英文字母字符('a' - 'z')组成,表示单词S
输出量:输出应为b+ 1 −a字符序列,表示扩展单词S′中从第a到第b的字母换句话说,假设B-n个字母已经被添加到初始单词S,你想打印最后一个B+ 1 −a
示例:对于输入数据:
11 3 12 13 abaaabababa
正确的结果是:
BA
我已经成功地创建了一个程序,它可以正确地构建字符串,但是当(b - n)(我们假设添加的字母数)很大时,它不能在合理的时间内完成。b可以大到10^18,n只能大到10^6,剩下10^18 - 10^6个字符要生成。另一方面,我们只关心b - a + 1个字符,最多只有100万个字符,而我正好赶上了。我相信我在处理这个问题上的想法是错误的。我确信我们实际上不应该生成整个字符串,因为我运行的所有测试似乎都生成了一个模式,这个模式迟早会开始。也许我们应该只生成所需的字符量,然后旋转字符串(滚动它)?任何形式的帮助都是感激的。如果你相信你知道可以帮助我的资源,我会很高兴。我很难寻找合适的解决方案。这个任务是关于一个虚构的聊天机器人,也许一些机器学习算法会做的伎俩?
这是我的简化代码(在原来的一个我使用基数特里与自定义散列,但这并不重要,我相信,两个程序生成正确的结果)。

[[nodiscard]] static std::string Model(
    const size_t n,
    const size_t k,
    const size_t a,
    const size_t b,
    std::string& word) noexcept(true)
{
    /* k-lettered substring -> character after the substring -> count */
    std::unordered_map<std::string, std::unordered_map<char, size_t>> occurences;

    for (size_t i{ 0U }; i < n - k; ++i)
        /* Extract a k-lettered substring at position i -> extract the letter after it -> increate count */
        ++occurences[word.substr(i, k)][word[i + k]];

    std::string lettersToPrint{};
    for (size_t i{ 0U }; i < (b - n) /* Do we really have to generate all of them? */; ++i)
    {
        /* k-lettered substring at the end of the "word". */
        std::string suffix(word.substr(word.length() - k, k));

        /* Detect the most popular character occurring after each suffix substring. */
        size_t mostPopularSuffixAppendLetterCount{ 0U };
        char mostPopularSuffixAppendLetter{ 'a' };

        for (char j{ 0 }; j < 26; ++j)
        {
            // careful! works with ASCII!!!
            const char currentCharacter{ char('z' - j) };
            const auto currentCharacterCount{ occurences[suffix][currentCharacter] };

            if (currentCharacterCount >= mostPopularSuffixAppendLetterCount)
            {
                mostPopularSuffixAppendLetterCount = currentCharacterCount;
                mostPopularSuffixAppendLetter = currentCharacter;
            }
        }

        word += mostPopularSuffixAppendLetter;

        if ((b - n) - i <= b + 1 - a)
            lettersToPrint += mostPopularSuffixAppendLetter;
    }

    return lettersToPrint;
}

int main()
{
    size_t n{ 65 }, k{ 2 }, a{ 67 }, b{ 783 };
    std::string word{ "ffdedffddfdefedddfdfddfddeedfdededddffeefffdeedfeddeddddfeefdffee" };

    assert(Model(n, k, a, b, word) == "dfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddfdeddf");

    return 0;
}

字符串

tvz2xvvm

tvz2xvvm1#

因为这是作业,我就不给予你完整的答案了,让你自己去理解。
以下是一些提示:
1.是否有重复出现在字符串延续中?
1.你能证明吗?
1.如果有重复,它的最大长度是多少?
1.你能在不生成整个延续的情况下检测出重复从哪里开始吗?
1.你能用这些信息找到最后(B + 1 - a)个字符的延续吗?

相关问题