【问题标题】: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
  • 我已经编辑了输出,因为它有太多错误

标签: c++


【解决方案1】:

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

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

  1. char 已经出现并且 char 的最后出现要求您移动潜在匹配的开头以避免 char 出现两次:更新答案,匹配在当前 char 之前结束,如果这比当前答案。
  2. 否则:只需更新地图
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】:

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

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

    DemoDemo using a bitset&lt;&gt; instead

    【讨论】:

      猜你喜欢
      • 2016-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-26
      • 2023-03-31
      • 2020-04-27
      • 2021-07-24
      • 2020-12-09
      相关资源
      最近更新 更多