【LeetCode-滑动窗口】最长不含重复字符的子字符串
题目描述
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
说明:
- s.length <= 40000;
- 这题是《剑指Offer》的第 28 题;
题目链接: https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/
思路1
使用滑动窗口来做。窗口的范围为 [left, right],left,right 初始化为0。设置一个查找表 lookup,lookup 存储了当前窗口中的元素。right 先移动,如果 s[right] 不在 lookup 中,则 right++,maxLen++,将 right 加入 lookup 中;否则,将 s[left] 从 lookup 中移除(注意这里不是先移除重复的元素 s[right],因为先移除 s[right] 的话就不满足连续子串这个要求了),将 left++,直至 s[right] 不在 lookup 中出现。代码如下:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.empty()) return 0;
unordered_set<char> lookup;
int left = 0;
int right = 0;
int maxLen = 1; // 初始化为 1
while(right<s.size()){
if(lookup.count(s[right])==0){ // s[right]不在lookup中出现
lookup.insert(s[right]); // 先 insert,再将 right++
right++;
maxLen = max(maxLen, right-left);
}else{
if(!lookup.empty()){
lookup.erase(s[left]);
left++;
}
}
}
return maxLen;
}
};
思路2
在思路 1 中,当遇到了重复字符,我们一步一步地移动 left 指针。为了加快速度,我们可以直接将 left 移动到当前 right 的位置上。
代码如下:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.empty()) return 0;
vector<int> v(128, -1);
int left = -1;
int maxLen = 1;
for(int right=0; right<s.size(); right++){
char c = s[right];
if(v[c]!=-1) left = max(left, v[c]); // c 出现在了窗口中
v[c] = right;
maxLen = max(maxLen, right-left);
}
return maxLen;
}
};