最长的子字符串,C++中只有 2 个不同的字符

Longest substring with only 2 distinct chars in C++

本文关键字:字符 字符串 C++      更新时间:2023-10-16

我正在尝试找到最多包含 2 个不同字符的最长子字符串。它是一个蛮力程序,它只使用所有可能的子字符串并检查它们是否有 2 个或更多不同的字符。

我使用一组来跟踪不同的字符。

#include <iostream>
#include <string>
#include <algorithm>
#include <unordered_set>
using namespace std;
int main()
{
   string s = "AllPossibleSubstrings";
   int l=0,index=0;
   for(int i =0;i<s.length();i++)
   {
       for(int j=i+1;j<s.length();j++)
       {
           string sub = string(s.begin()+i,s.begin()+j);
           unordered_set<char> v;
           for(auto x:sub)
           {
               v.insert(x);
           }
           if(v.size()<=2) {l=max(l,j-i+1); if(l==j-i+1) index=i;}
       }
   }
   cout<<l<<" "+s.substr(index,l)<<endl;
}

我得到4 ssib的错误答案,而正确答案一定没有b(All,llP,oss,ssi是可能的答案(。我哪里做错了?

如果将

调试输出添加到代码以查看它找到哪些字符串:

if(v.size()<=2) {
    l=max(l,j-i+1); 
    if(l==j-i+1) {
        index=i;
        cout << "Found match " << i << " " << j << " " << l << " " << sub << endl;
    }
}

你会看到它找到了正确的字符串:

Found match 0 1 2 A
Found match 0 2 3 Al
Found match 0 3 4 All
Found match 1 4 4 llP
Found match 4 7 4 oss
Found match 5 8 4 ssi

(见这里:http://ideone.com/lQqgnq(

但是你也会看到,例如,对于i=5j=8你得到sub="ssi",但l=4,这显然是错误的。

因此,错误行为的原因是string(s.begin()+i,s.begin()+j)使子字符串从第 i 个字符开始,直到(但不包括(第 j 个字符:http://www.cplusplus.com/reference/string/string/string/:

template <class InputIterator>
   string  (InputIterator first, InputIterator last);

复制范围 [first,last( 中的字符序列 相同的顺序。

请注意,不包括last

所以你的l应该相应地计算:如j-i,而不是j-i+1


事实上,原因是你的代码过于复杂。你在代码末尾显然使用了s.substr,为什么不在主循环中使用相同的?你甚至可以循环il,然后你就不会有这样的问题。

此外,实际上您不需要每次都提取子字符串。您可以循环遍历il,只需保留一组不同的字符即可。这将产生更快的O(N^2)解决方案,而您的解决方案O(N^3).像这样:

for (int i=0; i<s.length(); i++) {
   unordered_set<char> v; 
   for (int l=1; l<s.length()-i; l++) 
       v.insert(s[i+l-1]);
       if (v.size()>2) break;
       if (l>maxl) {
            index = i;
            maxl = l;
       }
}

事实上,即使是O(N)解决方案也可以在这里实现,但需要更高级的代码。

问题是 l 变量是子字符串的长度 + 1...请注意,j 索引是子字符串最后一个字符之后的一个索引。

所以,为了正确处理它:

将 if 语句更改为:

   if(v.size()<=2) {l=max(l,j-i); if(l==j-i) index=i;}

我修改了您的代码,如果我做对了,答案是找到的任何代码,如果您希望将它们存储在数组或其他东西中并显示所有相同大小(最长(。这是你能得到的尽可能多的蛮力。

#include <iostream>
#include <string>
#include <algorithm>
#include <unordered_set>
using namespace std;
int main(int args, char argv[]){
    string s = "AllPossibleSubstrings";
    string output = string();
    int starts_from = 0, length = 0;
    for (int i = 0; i < s.length(); i++){
            string sub = string();
            sub += s[i];
            int characters = 1;
            bool not_found = false;
            for (int j = i + 1; j < s.length() && characters <= 2; j++){
                for (int k = 0; k < sub.length(); k++)
                    if (s[j] != sub[k])
                        not_found = true;
                    if (not_found && characters == 1){
                        sub += s[j];
                        characters++;
                    }
                    else if (not_found && characters == 2)
                        break;
                    else
                        sub += s[j];
            }

            if (sub.length() > length){
                length = sub.length();
                starts_from = i; // index + 1 for the >1 value
                output = sub;
            }
    }
    cout << endl << "''" << output << "''" << " which starts from index " << starts_from << " and is " << output.length() << " characters long.." << endl;
    system("pause");
    return 0;
}
使用

char* 指针比使用 String 类更容易,后者更像 Java 的方法。然后,使用与嵌套循环相同的算法结构并计算子字符串长度(从第一个到下一个大写字母(,如果它比任何其他子字符串长,则使用 char* 进行新的分配,或者创建一个新的 String 对象(如果必须使用 String 类(。当然,您从最长的值 0 开始:

unsigned int longest_substring = 0;

如果找到更大的值,正如我已经说过的,你把它更改为它的长度,然后重新分配输出字符串(char[]/char*(变量。

要使所有这些工作,您需要循环计数器,longest_string,current_string(用于在嵌套循环中检查的子字符串的长度(,当然还需要char*/String来存储到目前为止最长的子字符串。

我很着急,所以我无法提供代码,但这就是逻辑:-(

算法很好(当然,它是蛮力的,没什么花哨的(。但是,内部循环中生成的子字符串被误解了。

子字符串从索引 i 到索引 j-1(都包括在内(,它不包括索引 j。因此,子字符串的长度必须是 (j-1 - i +1( = j-1 。索引和长度变量必须使用此正确的长度进行更新。

这是错误的根源。顺便说一下,在可能的答案中,算法根据字符串中的位置返回最后一个子字符串。

也许最好重写你的代码:

#include <iostream>
#include <string>
using namespace std;
int main()
{
   string s = "AllPossibleSubstrings";
   int max=0,index=0;
   for(int i =0;i<s.length();i++)
   {
       int j=i;
       for(;s[j]==s[i];j++);
       if((j-i+1)>max)
       {
       max = (j-i+1);
       index = i;
       }
   }
   cout<<max<<" "+s.substr(index,max)<<endl;
}

编辑还应该再添加一个检查。结果是循环的主体将变为这样:

   int j=i+1;
   for(;(s[j]==s[i] && j<n);j++);
   if(j==n) break;
   int z=j+1;
   for(;(s[z]==s[i]||s[z]==s[j]);z++);
   if((z-i)>max)
   {   
   max = (z-i);
   index = i;
   }