一、题目描述
官方链接:无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是子串的长度,"pwke" 是一个子序列,不是子串。
二、题目解析
这里用到的主要思想就是滑动窗口。
什么是滑动窗口呢?举个栗子!
对于"pwwkew"
来说
1.窗口为空。
2.往后移动,将字符'p'加入窗口。 窗口:p
3.继续往后移动,将字符'w'加入窗口。 窗口:pw
4.下面这个字符是'w',因为'w'已经在窗口内了,
而要求不能有重复字符,所以窗口往后移动舍弃前面得到的。 窗口:w
5.继续往后移动,将字符'k'加入窗口。 窗口:wk
6.继续往后移动,将字符'e'加入窗口。 窗口:wke
7.下面这个字符是'w','w'已经在窗口内了,
所以窗口舍弃前面得到的,将该'w'加入窗口。 窗口:w
注:当然,不是每次窗口都是舍弃所有旧的元素,开始添加新的元素,比如字符串"abca",当扫描到最后一个字符'a'的时候,此时窗口只要舍弃掉最前面的'a',把新的'a'加进去就可以了,也就是说,窗口由"abc"-->"bca"。
所以滑动窗口就是,每次将符合要求的元素加入到窗口中,并且根据要求的条件,不断地扩大或者移动窗口。
一般是用队列实现滑动窗口比较好,对于不同的题目可以选择不同的数据结构,但个人觉得,滑动窗口就是个天然的队列结构。
那么对于这道题,我们只需要设置一个max
,在每次窗口需要滑动的时候,对比窗口大小和max
值,及时更新max
就好了。
对于上面的例子,就是在第4
步max=2
(更新窗口前先更新max
),在第7
步max=3
。
三、代码
class Solution {
public:
int lengthOfLongestSubstring(string s) {
queue<char> q;
int flag[150],max = 0;
for (int i = 0; i < 150; i++)
flag[i] = 0;
for (int i = 0; i < s.length(); i++) {
if(flag[s[i]] == 0){ // 如果 flag为0,说明该元素没有在窗口中,那么将该元素加入窗口。
q.push(s[i]);
flag[s[i]] = 1; // 加入窗口后,该元素的 flag赋值为1。
}
else { // 否则,该元素已经在窗口中了,此时要移动窗口
// 先更新 max,如果窗口大小大于 max,那么将 max赋值为窗口的大小,如果题目要求输出最长的字串,那么在这里可以将此时的窗口元素保存
max = max > q.size() ? max : q.size();
// 移动窗口,将重复元素及其前面的元素全部踢出窗口
while(!q.empty()){
if(q.front() == s[i]){
q.pop();
break;
}
// 将元素踢出窗口时,该元素的 flag赋值为 0
flag[q.front()] = 0;
q.pop();
}
q.push(s[i]); // 将新的元素加入窗口
}
}
// 更新 max
max = max > q.size() ? max : q.size();
return max;
}
};