题目描述
给定一个字符串 s
,请你找出其中不含有重复字符的 最长 子串 的长度。
示例 1:
输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 示例 2: 输入: s = "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是“b”,所以其长度为 1。 示例 3: 输入: s = "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是"wke",所以其长度为 3。 提示: 0 <= s.length <= 5 * 104 由英文字母、数字、符号和空格组成
一、模板介绍
正如标题所述,该题会用到滑动窗口的思想,那么什么是滑动窗口以及什么时候使用呢?
顾名思义,滑动窗口就是可滑动的窗口,这里的窗口即代表所包含的子串,滑动代表所包含的子串可以依次滑动(一般都是从左到右滑动),我们只需要创建两个指针(广义指针,并非术语指针)来表示窗口的左右边框,就可以表示该滑动窗口。
那创建完窗口后怎么操作捏?让右指针先右移1,判断现在的子串是否符合题目要求。如果符合右指针就继续右移;如果不符合左指针右移1,并判断现在是否符合,不符合则继续移动。
//以下是该模板伪代码
初始化left,right,ans //left表示左指针,right表示右指针,ans是最终结果
while(right<字符长度)
{
while(当前窗口内子串不符合要求)
{
left++;
continue;
}
//接下来的操作代表该子串符合要求,则更新ans,并扩大右指针
更新ans;
right++;
}
非常通俗的讲,就是两个指针,一般是右指针移动,不符合条件就左指针移。
那么什么时候使用呢?在题目要求最长最短子串时可以考虑这么做。
tips:该模板有一个潜在要求就是如果当前子串不符合要求,那右指针再扩大后的子串也一定不符合要求,所以才将左指针移动。像求最长回文子串就不符合这个模板。(如leetcode5--原题链接)
二、解题碎碎念
1.首先要明白子串和子序列的区别,子串必须是连续的,而子序列可以从串中随意抽取字符,即子序列不要求连续。
2.在了解滑动窗口之后,我们可以尝试解题。对于模板,所要做的是怎么判断当前字符是否符合要求,即无重复字符。对于初学者来说,可以构造一个判断函数,在右指针扩大1后,判断右指针指向的字符与之前字符串之间是否有相同字符。
//一个简单的判断函数
#include<stirng>
bool NotExist(string a, char b,int start,int end)
{
for (int i = start; i < end ; i++)
{
if (b == a[i])
return false;
}
return true;
}
更新ans是做一个简单的if判断或一个三目运算
if (ans < (end - start + 1))
ans = end - start + 1;
3.放到力扣上跑的话,会发现这样做的时间比较高,所以可以尝试用标准模板库中的模板,如unordered_set, (对于该模板的使用,笔者不再赘述,大家可以自行查找)。
//以下是使用unordered_set的核心函数,记得包含<unordered_set>头文件
int lengthOfLongestSubstring(string s) {
int start = 0, end = 0, ans = 0;
unordered_set<char> win;
int len = s.length();
while (end < len) //滑动窗口
{
while (win.count(s[end])) //不符合要求,扩大左指针,缩小子串
{
win.erase(s[start]);
start++;
continue;
}
win.insert(s[end]);
if (ans < end - start + 1) //更新ans
ans = end - start + 1;
end++; //扩大右指针
}
return ans;
总结
以上就是今天分享的内容,其实把上面的代码放到力扣上跑会发现时间也没有很快,因为更高效的方法我也没有学习啦,嘎嘎(  ̄з(〃´▽`〃)ε ̄ )