写在前面:
题目链接:LeetCode - 3. 无重复字符的最长子串
题目难度:中等
编程语言:C++
一、题目描述
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成
二、题目分析&解题思路
2.1 暴力法
先没有做题思路,老规矩,先试试暴力法:
这里发现,我们只要发现了重复的字符后面的就可以不继续罗列了,例如上图,我们只需要拿到,pw、wke 即可
2.1.1暴力法代码示例:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.size() <= 1)
{
return s.size();//注意边界值
}
int left = 0;
int imax = 0;//最大的长度
while(left < s.size())
{
int itemp = left;
string strTemp = "";
while(itemp < s.size())
{
if(strTemp.find(s[itemp])!=string::npos)
{
if(imax < strTemp.size())
{
imax = strTemp.size();
}
strTemp = "";
break;//遇到有重复的直接break 即可
}
else
{
strTemp+=s[itemp];
}
itemp++;
}
if(!strTemp.empty())//最后一次结果
{
if(imax < strTemp.size())
{
imax = strTemp.size();
}
}
left++;
}
return imax;//最大长度
}
};
运行结果:
居然过了,但是可以看击败 9.90% 就有点鸡肋了,O(n^2) 的时间复杂度的确有点太拉了,我们再试试看有没有别的方法:
2.2 滑动窗口法:
换种思路:
这里我们 遍历到 pww 之后发现 w 重复,那么则需要将左侧的 p、w依次删除掉,直到 不重复为止。
继续:
这其实就是滑动窗口的思想,一个窗口从左至右选择,遇到重复的就将窗口左侧的字符删除掉,保证窗口内的是不重复的,并且将每次的结果记录下来即可。
2.2.1滑动窗口代码示例:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int max = 0;
unordered_set<char> unSet;//unordered_set无序性与键值唯一性
int left = 0;
for(int i = 0; i < s.size();i++)
{
while(unSet.find(s[i]) != unSet.end())
{
unSet.erase(s[left]);//删除最左侧元素
left++;
}
if(max < i-left+1)//记录最大值
{
max = i-left+1;
}
unSet.insert(s[i]);
}
return max;
}
};
运行结果:
感觉效率也不是很高,才击败一半的人,然后拷了官方题解,也只击败了一半的人,emmmm 有更好的解法欢迎大家讨论。