3.无重复字符串的最长子串
一、问题描述
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
二、问题简化
这个问题本质上是:
“从一个数组中,寻找最长的子串,其元素均不相同”。
这里说下子串和子序列的区别:子串是必须连续的,而子序列不一定连续,但它们的顺序是和原数组相同的。
字符串本质是字符的数组,所以我们使用模板使其更通用化比较恰当。
并且返回值仍然可以是多个。
所以整个函数可以表示为:
template<typename T>
vector<T> GetSubLongest(const T& container)
三、功能实现
1.遍历整个序列,iter0记为下标。
2.从iter0遍历到结束作为子串,或提前出现了不同元素。
3.第2步中保存的子序列,与最长长度判断。如果更长,则删除旧元素,加入自己到结果。如果一样长就只加入自己到结果中。如果更短,iter0自增,进入下一个子串的开始。
template<typename T>
vector<T> GetSubLongest(const T& container)
{
vector<T> ret;
int max_size = 0;
T sub;
//如果比最大长度长,则加入返回值且更新最大长度
auto fn_addSub = [&]()
{
if (sub.size() > max_size)
{
ret.clear();
ret.push_back(sub);
max_size = sub.size();
}
else if (sub.size() == max_size)
{
ret.push_back(sub);
}
};
for (auto iter0 = container.begin(); iter0 != container.end(); ++iter0)
{
sub.clear();
auto iter1 = iter0;
sub.push_back(*iter0);
while (true)
{
++iter1;
if (iter1 == container.end())
{
//判断加入,然后中断
fn_addSub();
break;
}
auto iter_f = find(sub.begin(), sub.end(), *iter1);
if (iter_f == sub.end())
{//如果不是重复元素,则添加到sub
sub.push_back(*iter1);
}
else
{//重复了,则检测是否加入到返回值
//判断加入,然后中断
fn_addSub();
break;
}
}
}
return ret;
}
四、测试结果
//输入值如下:
"我爱中国,中国爱我!"
{ 1,1,2,5,3,2,2,7,8,8,9,1,0 }
"abcabcbb"
"pwwkew"
可以看到,不仅对字符串有用,还对数字有效,甚至于任何事物(只要它们可以比较是否相同),这就是模板泛型算法的魅力。
在判断子序列是否比以往的更长时,由于它会出现两次,所以我写成了lambda表达式。尽量防止代码重复出现,是我编程的原则之一。
还有我使用的是wstring字符串,而不是string。前者是utf-16编码,任何字符都只算一个。如果使用string,中文会算作两个,这样算法就不可能正确处理汉字的相同判断。在使用wcout输出时,需要设置一下本地化环境,调用wcout.imbue(locale("chs"));即可,但这还不是最通用化的写法,暂时这样吧。
完整的代码如下:
//3.无重复字符串的最长子串
#include <iostream>
#include <string>
#include <list>
#include <vector>
using namespace std;
template<typename T>
vector<T> GetSubLongest(const T& container)
{
vector<T> ret;
int max_size = 0;
T sub;
//如果比最大长度长,则加入返回值且更新最大长度
auto fn_addSub = [&]()
{
if (sub.size() > max_size)
{
ret.clear();
ret.push_back(sub);
max_size = sub.size();
}
else if (sub.size() == max_size)
{
ret.push_back(sub);
}
};
for (auto iter0 = container.begin(); iter0 != container.end(); ++iter0)
{
sub.clear();
auto iter1 = iter0;
sub.push_back(*iter0);
while (true)
{
++iter1;
if (iter1 == container.end())
{
//判断加入,然后中断
fn_addSub();
break;
}
auto iter_f = find(sub.begin(), sub.end(), *iter1);
if (iter_f == sub.end())
{//如果不是重复元素,则添加到sub
sub.push_back(*iter1);
}
else
{//重复了,则检测是否加入到返回值
//判断加入,然后中断
fn_addSub();
break;
}
}
}
return ret;
}
int main()
{
wcout.imbue(locale("chs"));
//0
auto ret = GetSubLongest(wstring(L"我爱中国,中国爱我!"));
for (auto& iter : ret)
{
wcout << iter << endl;
}
wcout << endl;
//1
auto ret1 = GetSubLongest(list<int>({ 1,1,2,5,3,2,2,7,8,8,9,1,0 }));
for (auto& iter : ret1)
{
for (auto& iter1 : iter)
{
wcout << iter1;
}
wcout << endl;
}
wcout << endl;
//2
auto ret2 = GetSubLongest(wstring(L"abcabcbb"));
for (auto& iter : ret2)
{
for (auto& iter1 : iter)
{
wcout << iter1;
}
wcout << endl;
}
wcout << endl;
//3
auto ret3 = GetSubLongest(wstring(L"pwwkew"));
for (auto& iter : ret3)
{
for (auto& iter1 : iter)
{
wcout << iter1;
}
wcout << endl;
}
wcout << endl;
}