1. 引言
本文将会介绍如何使用C++代码找到具有一个最小子字符串的两个子字符串。
2. 什么是最小子字符串
子字符串是指原字符串中的连续一段字符。最小子字符串是指子字符串中所有字符均不相同的最短长度。
3. 解决方法
3.1 暴力解法
暴力解法即为枚举出所有子字符串,再遍历每个子字符串的字符,判断是否有重复字符,取长度最短的即可。
实现如下:
int minSubstr(string str)
{
int len = str.length();
int res = len;
for (int i = 0; i < len; i++)
{
for (int j = i + 1; j < len; j++)
{
int tempLen = j - i + 1;
bool flag = true;
for (int k = i; k < j; k++)
{
for (int t = k + 1; t <= j; t++)
{
if (str[k] == str[t])
{
flag = false;
break;
}
}
if (!flag)
break;
}
if (flag && tempLen < res)
res = tempLen;
}
}
return res;
}
时间复杂度为O(n^3),显然对于较长的字符串,计算时间会很长。
3.2 滑动窗口
由于暴力解法太过耗时,我们可以考虑优化解法。相比于暴力解法,我们需要找到更高效的方法快速地找到最小子字符串。为此,我们可以使用滑动窗口。
滑动窗口就是维护一个窗口,根据条件不断地调整窗口大小。
我们设一个左指针left和一个右指针right。刚开始left和right同时指向字符串的第一个字符,然后我们将right往右移动。当right指针指向的字符在[left,right-1]中出现过,我们就将left指针移动到重复字符的位置的下一个位置,此时窗口大小为right-left。当right指针指向的字符没在[left,right-1]中出现过时,我们将right指针继续往右移动。当right指针指向的字符与[left,right-1]中的所有字符都不相同时,我们仍将窗口大小右移,也即将res取min(right-left+1,res)。
实现如下:
int minSubstr(string str)
{
int len = str.length(), res = len + 1;
int left = 0, right = 0;
unordered_set s;
while (right < len)
{
if (s.find(str[right]) == s.end())
{
s.insert(str[right]);
right++;
res = min(res, right - left);
}
else
{
s.erase(str[left]);
left++;
}
}
return res;
}
4. 总结
从暴力解法到滑动窗口,我们寻找最小子字符串的过程逐渐变得高效。在实际开发中,我们需要尽可能减少计算时间,使程序运行更快。