题目
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度
提示:0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成
思路
首先要注意的是:
- 子串要求连续
- 子序列可以不连续
本题的主要思路是:滑动窗口
滑动窗口:其实就是一个队列,比如例子中的abcabcbb,进入这个队列为abc时满足题意,当再进入a,窗口中变成了abca,不满足要求所以要移动这个队列,只需要将队列左边的元素移出就行了,直到满足题意为止
一直维持这样的队列,找出队列出现的最长长度的时候,即为解
简单来说就是,滑动窗口里面是符合要求的部分,然后扩大右边界,如果不符合要求了,就缩小左边界,直到窗口内的内容又满足题意了,然后接着扩大右边界
时间复杂度0(n)
java代码如下:
class Solution {
public int lengthOfLongestSubstring(String s){
//维护当前最长不重复字符子串
Set<Character> set = new HashSet<>();
int left = 0;//滑动窗口的左边界,用于移除左边元素,动态变化
int right = 0;//滑动窗口的右边界,用于找后面的元素,表示目前滑动到的元素位置,动态变化
int max = 0;//滑动窗口最大长度
while(right < s.length()){
if(!set.contains(s.charAt(right))){
//如果没有查到重复元素,就加到set中,right右移
set.add(s.charAt(right));
right++;
} else {//如果遇到了重复元素
//right查到重复元素先不动,将left右移,set删除left经过的字符,直到删除掉右边这个重复的字符(即right的值),如abcb->bcb->cb停
set.remove(s.charAt(left));
left++;
}
//每一次循环计算当前set子串里的长度
max = Math.max(max,set.size());
}
return max;
}
}
滑动窗口相关题目:
76. 最小覆盖子串
30. 串联所有单词的子串
209. 长度最小的子数组
239. 滑动窗口最大值
567. 字符串的排列
最后补充一些东西:很多人把 双指针 和 滑动窗口 混为一谈,但从狭义的角度来说
- 滑动窗口是一类问题,同向移动
滑动窗口的概念始于TCP,滑动窗口应当是左指针始终向右移动,右指针不停变化,也就是窗口长度不停变化但整体是向一个方向移动的。也就是说需要使用适合的数据结构来解决(或者说维护这个窗口),例如单调队列、平衡树等等。
- 而双指针是一种解决方法,可以同向或双向移动
双指针又分成左右指针和快慢指针
(1)快慢指针:主要解决链表中的问题,一般为同向移动,比如判定链表中是否包含环
(2)左右指针:主要解决数组(或者字符串)问题,可以是双向移动(同向或者反向),一般为固定一个边界并改变另一个边界来不断逼近约束要求,比如二分搜索