是否有用于查找字符串中最长且不重复长度的子字符串的结构函数?

Posted

技术标签:

【中文标题】是否有用于查找字符串中最长且不重复长度的子字符串的结构函数?【英文标题】:Is there a struct function for finding the longest and not-repeating length substring within a string? 【发布时间】:2021-01-23 08:32:50 【问题描述】:

函数的目的是找出最长且不重复的子串,所以我需要找出子串的起始位置和长度。我正在努力解决的问题是大 O 符号应该是 O(n)。因此我不能使用嵌套的 for 循环来检查每个字母是否重复。 我创建了一个这样的结构函数,但我不知道如何继续:

struct Answer              
    int start;              
    int length;
;
Answer findsubstring(char *string)
    Answer sub=0, 0

    for (int i = 0; i < strlen(string); i++) 
        
    
    return (sub)

例如输入为HelloWorld,输出应为World,长度为5。 如果输入为abagkfleoKi,则输出为bagkfleoKi。长度为 10。 另外,如果两个字符串的长度相同,则选择后一个。

【问题讨论】:

"HelloW" 不是包含重复的'l's 吗? 抱歉,HelloWorld 的输出应该是 'orld' 为什么不World 为什么第二种情况的输出不是bagkfleoKi 我已经编辑了输出,因为它有太多错误 【参考方案1】:

使用std::unordered_map&lt;char, size_t&gt; 存储某个字符最后一次出现之后的索引。

保留当前最佳匹配以及您当前测试的匹配。在需要处理的 2 种情况下遍历输入结果的字符:

    char 已经出现并且 char 的最后出现要求您移动潜在匹配的开头以避免 char 出现两次:更新答案,匹配在当前 char 之前结束,如果这比当前答案。 否则:只需更新地图
void printsubstring(const char* input)

    std::unordered_map<char, size_t> lastOccurances;

    Answer answer 0, 0 ;

    size_t currentPos = 0;
    size_t currentStringStart = 0;

    char c;

    while ((c = input[currentPos]) != 0)
    
        auto entry = lastOccurances.insert( c, currentPos + 1 );

        if (!entry.second)
        
            if (currentStringStart < entry.first->second && currentPos - currentStringStart > answer.length)
            
                // need to move the start of the potential answer
                // -> check, if the match up to the char before the current char was better
                answer.start = currentStringStart;
                answer.length = currentPos - currentStringStart;
                currentStringStart = entry.first->second;
            
            
            entry.first->second = currentPos + 1;
        
        ++currentPos;
    

    // check the match ending at the end of the string
    if (currentPos - currentStringStart > answer.length)
    
        answer.start = currentStringStart;
        answer.length = currentPos - currentStringStart;
    

    std::cout << answer.start << ", " << answer.length << std::endl;
    std::cout << std::string_view(input + answer.start, answer.length) << std::endl;

【讨论】:

【参考方案2】:

我将概述一种可能的解决方案。

    您需要两个循环。一个指向子字符串的开头,一个指向结尾。
    auto stringlen = std::strlen(string);
    for(size_t beg = 0; beg < stringlen - sub.length; ++beg) 
        // See point 2.
        for(size_t end = beg; end < stringlen; ++end) 
            // See point 3.
        
    
    
    创建已在子字符串中看到的字符的“黑名单”。
    bool blacklist[1 << CHAR_BIT]; // zero initialized
    
    检查当前end字符是否已经在blacklistbreak中,如果是,则将其放入黑名单。
    if(blacklist[ static_cast<unsigned char>(string[end]) ]) break;
    else 
        blacklist[ static_cast<unsigned char>(string[end]) ] = true;
        // See point 4.
    
    
    检查当前子字符串的长度 (end - beg + 1) 是否大于您当前拥有的最长长度 (sub.length)。如果更长,存储sub.start = begsub.length = end - beg + 1

Demo 和 Demo using a bitset&lt;&gt; instead

【讨论】:

以上是关于是否有用于查找字符串中最长且不重复长度的子字符串的结构函数?的主要内容,如果未能解决你的问题,请参考以下文章

最长不含有重复字符的子字符串

符串的最长无重复字符的子串长度

新增5 最长不含重复字符的子字符串

剑指 Offer 48. 最长不含重复字符的子字符串

后缀树

剑指offer:最长不含重复字符的子字符串