题目描述
给定一个字符串
s
,请你找出其中不含有重复字符的 最长子串 的长度。
示例1
输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例2
输入: s = "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例3
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
做题思路
在寻找不含有重复字符的最长字串的时候,我们可以通过依次递增地枚举子串的起始位置来实现。假设我们选择字符i个字符作为起始位置,并且得到了不包含重复字符的最长子串的结束位置为r。那么当我们选择第i+1个字符作为起始位置时i+1到r的字符是不重复的,并且由于少了i个字符,我们可以尝试继续增大r,直到右侧出现了重复字符为止。
这个过程我们可以通过滑动窗口来实现:
- 使用两个指针i和r表示窗口的左右边界,i代表枚举自子串的起始位置,r为不含有重复字符的子串的右边界;
- 除了第一次枚举之后的每一次枚举,我们都会将左指针向右移动一格,表示开始枚举下一个字符作为起始位置,在保证左右指针对应的子串中没有重复字符的前提下不断地向右移动右指针,记录下每次枚举的子串的长度;
- 枚举结束后,找到的最长的子串的长度即为答案。
代码
class Solution {
public int lengthOfLongestSubstring(String s) {
int len=s.length();
if(len==0) return 0;
int res=0; //存储最后结果
int r=-1; //无重复字符的子串的右边界
Set<Character> set=new HashSet<Character>();
for(int i=0;i<len;i++){
if(i!=0){
set.remove(s.charAt(i-1)); //左指针向右移动一格,移除一个字符
}
while(r+1<len && !set.contains(s.charAt(r+1))){
set.add(s.charAt(r+1)); //只要无重复字符且不超过字符串长度,就不断添加新的字符
r++; //指针右移
}
res=Math.max(res,r-i+1); //每结束一次遍历,就记录下当前的最长子串的长度
}
return res;
}
}