无重复字符的最长子串
题目:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
思路:使用滑动窗口。我们以"abcabcbb"举例。从第一个字符出发,找出无重复字符的子串的最大长度。括号代表开始的字符以及无重复字符的子串。
以( a )bcabcbb开始的无重复最长子串为:( abc )abcbb
以a( b )cabcbb开始的无重复的最长子串为:a( bca )bcbb
以ab( c )abcbb开始的无重复的最长子串为:ab( cab )cbb
以abc( a )bcbb开始的无重复的最长子串为:abc( abc )cbb
以abca( b )cbb开始的无重复的最长子串为:abca( bc )cbb
以abcab( c )bb开始的无重复的最长子串为:abcab( cb )b
以abcabcb(b)b开始的无重复的最长子串为:abcabcbb(b)
如果我们依次递增地枚举子串的起始位置,那么子串的结束位置也是递增的!这里的原因在于,假设我们选择字符串中的第 k 个字符作为起始位置,并且得到了不包含重复字符的最长子串的结束位置为 rk 。那么当我们选择第 k+1 个字符作为起始位置时,首先从 k+1 到 rk 的字符显然是不重复的,并且由于少了原本的第 k 个字符,我们可以尝试继续增大rk,直到右侧出现了重复字符为止。
这时候就能使用滑动窗口,定一个右指针right
,表示无重复最长子串的右边界,然后right
每向右移动一次,就需要判断当前指向的字符是不是已经在现有的子串中重复,如果不重复就添加到集合中,如果重复,左指针向右移动一次。这个判断重复我们可以使用哈希集合来做。当左指针向右移动一次时,我们将哈希集合中的第一个元素移除即可。
代码实现:
public int lengthOfLongestSubstring(String s) {
Set<Character> set = new HashSet<>();
int n = s.length();
// 右指针为-1,相当于最开始还没有移动。
int right = -1;
int answer = 0;
// i充当左指针
for(int i = 0; i<n;i++){
if(i!=0){
set.remove(s.charAt(i-1));
}
while(right+1< n && !set.contains(s.charAt(right+1))){
set.add(s.charAt(right+1));
right++;
}
answer = Math.max(answer,right-i+1);
}
return answer;
}