C++中最长的非重复子串

Longest Non Repeating Substring in c++

我正在尝试查找没有重复字符的最长子字符串。 我有一个布尔向量来跟踪 256 个 ascii 字符。

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>

using namespace std;

int main()
{
    string s = "aaaaaaaaaaaaasadfrhtytbgrbrsvsrhvsg";
    vector<bool> v(256, false);
    int j = 0, len = 0, index = 0;

    for(int i = 0; i < s.length(); i++)
    {
        if(!v[s[i]])
        {
            j++;

            if(j > len)
            { 
                len = j;
                index = i - j;
            }

            v[s[i]] = true;
        }
        else
        {
            j = 0;
            v.clear();
        }
    }

    cout << s.substr(index, len) + " " << len << endl;
}

我能理解为什么它给出输出 adfrht 6 ,而正确的输出是 sadfrhty 8.

您得到错误结果的原因是基本方法缺少一些移动部分。您没有跟踪计算此所需的所有信息。您不仅需要跟踪您看到了哪些字符,还需要跟踪它们在字符串中的哪个位置(我假设您希望将其保持在 O(n) 复杂度)。

这样,当您看到以前遇到过的字符时,您需要重置 "consecutive non-repeated characters seen so far" 计数器以在 之前出现的相同字符之后开始你正在看,在当前位置。此外,到目前为止看到的所有字符,直到那个时候,都不再看到了,因为如果你想一想,它应该对你有意义。

这是您的实施中缺少的部分。另外,它没有跟踪最长字符串的位置,非常正确。

以下应该会产生您要查找的结果。

让我们知道您的家庭作业成绩:-)

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;

int main()
{
    string s = "aaaaaaaaaaaaasadfrhtytbgrbrsvsrhvsg";
    vector<bool> v(256,false);
    vector<int> seen_at(256);

    int longest_starting_pos=0, longest_length=0;

    int current_length=0;

    for (int i=0; i<s.length(); i++)
    {
        if (v[s[i]])
        {
            for (int j=i-current_length; j<seen_at[s[i]]; ++j)
                v[s[j]]=false;
            current_length=i-seen_at[s[i]]-1;
        }

        v[s[i]]=true;
        seen_at[s[i]]=i;
        if (++current_length > longest_length)
        {
            longest_length=current_length;
            longest_starting_pos=i-current_length+1;
        }
    }

    cout<<s.substr(longest_starting_pos, longest_length)+" "<<longest_length<<endl;
}

你的算法不正确。您的算法的问题在于,一旦它检查了一个字符,如果包含该字符的子字符串不是最长的,它就不会返回该字符再次检查它。第一个 s 正在检查长度为 2 的字符串 as,但是当找到下一个 a 时,忘记了 s,即使它可以使下一个子串更长。试试这个代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;

int main()
{
    string s = "aaaaaaaaaaaaasadfrhtytbgrbrsvsrhvsg";
    vector<bool> v(256,false);
    int longStart = 0;
    int longEnd = 0;
    int start = 0

    for (end = 0; end < s.length(); end++)
    {
        if (!v[s[end]])   // if character not already in the substring
        {
            v[s[end]] = true;

            if (end - start > longEnd - longStart)
            {
                longEnd = end;
                longStart = start;
            }
        }
        else   //the character is already in the substring, so increment the
               //start of the substring until that character is no longer in it
        {
            //get to the conflicting character, but don't get to the new character
            while ((s[start] != s[end]) && (start < end))
            {
                start++;
                v[s[start]] = false;
            }

            //remove the conflicting character
            start++;
            //don't set v[s[start]] to false because that character is still
            //encountered, but as the newly appended character, not the first
        }
    }

    longEnd++;    //make longEnd the index after the last character for substring purposes
    cout << s.substr(longStart, longEnd - longStart) + " " << (longEnd - longStart) << endl;
}

基本上这段代码所做的是保留一个 运行 子字符串,每当它遇到一个已经在子字符串中的字符时,它会递增子字符串的开头,直到新字符不再在子串,然后照常继续。如果该子字符串比以前认为最长的子字符串长,它还会在每次结尾递增时进行检查。这是 O(n) 我相信如你所愿。

此外,传播您的代码。如果您不能轻松阅读和调试代码,那么简洁的代码毫无意义。此外,如果您的代码有问题,请手动解决所有问题,以更好地了解它的工作原理和发生的情况。

希望对您有所帮助!