滑动窗口是通过双指针同向移动而解决的一类问题
经常用于数组或者字符串,求其满足条件的子序列或者子串,将原先需要嵌套循环问题,转换为单循环问题,降低时间复杂度
主要过程:窗口从0开始构建,右指针不断地扩大,直到满足(不满足)条件停止,改为扩大左指针即缩小窗口,直到再次不满足(满足)条件停止,再改为扩大右指针,直至遍历完数组或字符串
关键点在于:
右指针扩大的时候,什么时候满足条件停止
左指针收敛的时候,什么时候结束收敛
一般收敛的结果是要窗口内元素再次满足条件,即多次收敛(while循环)
即要找到左指针的正确位置
class Solution {
public int lengthOfLongestSubstring(String s) {
int len = s.length();
if(len == 0 ) return 0;
Queue<Character>que = new LinkedList<>();
Set<Character>st = new HashSet<>();
int ans = 1;
Character c;
Character p ;
for(int i=0;i<len;++i){
c = s.charAt(i);
if(!st.contains(c)){
st.add(c);
que.offer(c);
}else {
while(que.peek() != c){
p = que.poll();
st.remove(p);
}
p = que.poll();
que.add(p);
// st.remove(p);
}
ans = Math.max(ans,que.size());
}
return ans;
}
}
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int ans = 0;
int l = 0;
int len = nums.length;
int r = 0;
int sum = 0;
while(r<len){
//不满足条件 右端点前进
sum+=nums[r++];
//一单满足条件,缩减左端点
if(sum>= target) {
//;//这里的长度是r-l,而不是r-l+1因为r是指向的下一个元素
if(ans == 0 ) ans = r-l;
else ans = Math.min(ans,r-l)
//寻址最短的,在满足条件的基础上继续缩减左端点
while(sum >= target && l<=r) {
ans = Math.min(ans,r-l);
sum-=nums[l++];
}
}
}
return ans;
}
}
class Solution {
public int longestOnes(int[] nums, int k) {
int len = nums.length;
int l = 0;
int r = 0;
int ans = 0;
int usek = 0;
while(r<len){
//这里是:满足条件继续扩大右端点(持续扩大:满足继续扩大知直到不满足条件)
if(nums[r]==1 || (nums[r]==0 && usek < k)) {
if(nums[r]==0) usek++;
//这里的l r 我取的元素是从[l,r]左闭右闭
ans = Math.max(ans,r-l+1);
r++;
//不满足条件时左端点前进,一旦满足条件就去扩大右端点
}else if(usek >=k && l<r) {
if(nums[l] == 0 ){
usek--;
}
l++;
ans = Math.max(ans,r-l+1);
}else {
l++;
r++;
}
}
return ans;
}
}