题目:
给定一个字符串 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
由英文字母、数字、符号和空格组成
题解:
明显可以暴力解决,但是效率太低。所以这里使用滑动窗口的思想进行求解。可以想象成一个窗口,从数组开始不断向右滑动,使用滑动窗口的算法能够在每次迭代中只考虑一个字符的增加或删除,从而减少了不必要的计算。题目要求判断无重复字符的最长子串,可以用set来进行重复元素的判断。
具体算法步骤如下:
1. 定义一个无序集合(unordered_set)str,用于存储当前窗口中的字符,以判断是否有重复字符出现。
2. 初始化窗口的左指针i为0,右指针r为-1,代表初始窗口大小为0。
3. 进入主循环,从左到右遍历字符串s的每个字符。
4. 在每次迭代中,首先判断i是否大于0,即是否已经形成了窗口。如果是,则从集合str中移除窗口的左边界字符s[i-1]。
5. 在内层循环中,通过r向右扩展窗口,直到窗口的右边界r+1对应的字符在集合str中已经存在,或者到达字符串的末尾为止。每次扩展窗口时,将对应字符加入集合str中,并将右指针r向右移动一位。
6. 在内层循环结束后,此时得到了以当前字符s[i]作为右边界的最长无重复子串。根据窗口的左右指针计算窗口的长度r-i+1,并将其与之前的最大长度ans进行比较并更新。
7. 重复步骤4-6,直到遍历完整个字符串s,即得到最长无重复子串的长度ans。
最终返回ans作为结果,即为最长无重复字符子串的长度。
该算法的时间复杂度为O(N),因为我们只需要对字符串进行一次遍历。空间复杂度为O(N),主要用于存储无序集合str和一些额外的变量。
代码如下:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_set<char> str;
int n=s.size();
int r=-1,ans=0;
for(int i=0;i<n;i++){
if(i!=0){
str.erase(s[i-1]);
}
while(r+1<n&&!str.count(s[r+1])){
str.insert(s[r+1]);
r++;
}
ans=max(ans,r-i+1);
}
return ans;
}
};