3. 滑动窗口
1.概念:
滑动窗口协议(Sliding Window Protocol),该协议是 TCP协议的一种应用,用于网络数据传输时的流量控制,以避免拥塞的发生。该协议允许发送方在停止并等待确认前发送多个数据分组。由于发送方不必每发一个分组就停下来等待确认。因此该协议可以加速数据的传输,提高网络吞吐量。
滑动窗口算法其实和这个是一样的,只是用的地方场景不一样,可以根据需要调整窗口的大小,有时也可以是固定窗口大小。
滑动窗口算法(Sliding Window Algorithm)
Sliding window algorithm is used to perform required operation on specific window size of given large buffer or array.
滑动窗口算法是在给定特定窗口大小的数组或字符串上执行要求的操作。
This technique shows how a nested for loop in few problems can be converted to single for loop and hence reducing the time complexity.
该技术可以将一部分问题中的嵌套循环转变为一个单循环,因此它可以减少时间复杂度。
简而言之,滑动窗口算法在一个特定大小的字符串或数组上进行操作,而不在整个字符串和数组上操作,这样就降低了问题的复杂度,从而也达到降低了循环的嵌套深度。其实这里就可以看出来滑动窗口主要应用在数组和字符串上。
看到定长要想到滑动窗口
2.目的:
减少while循环
3.Leetcode
209. 长度最小的子数组
public int minSubArrayLen1(int target, int[] nums) {
if (nums.length == 0 || nums == null) {
return 0;
}
int i = 0;//头指针
int j = 0;//尾指针
int sum = 0; //记录和
int res = nums.length + 1; //赋初值,只要长度大于数组长度就行
while (j < nums.length) { //右指针小于长度
sum += nums[j]; //往后继续加
j++;
while (sum >= target) { //当加起来的大于目标值
res = Math.min(res, j - i); //返回的长度是j-i和res中最小的长度
sum -= nums[i]; //除去当前窗口第一个i的值
i++; //左指针右移
}
}
// 如果最终result的值等于数组长度+1,则表示不存在符合条件的子数组
return res == nums.length + 1 ? 0 : res;
}
题解:
- 定义两个指针i,j,i是头,j是尾
- i先不动,当 j指针 < 数组长度时,加起来的值 < 目标值,j 往右移动
- 当加起来的值大于目标值时,看看是不是最小的,让 加起来的值减去i指针上的值,同时i指针右移
- 如果最终result的值等于数组长度+1,则表示不存在符合条件的子数组
1456. 定长子串中元音的最大数目
向右移动 时,左边如果是元音 -1,右边如果是元音 +1
两种都用的滑动窗口方法,
但是第一种用了集合
第二种用了方法判断
public int maxVowels(String s, int k) {
if(s==null||s.length()==0||s.length()<k){
return 0;
}
//添加到集合里
HashSet<Character> set =new HashSet<>();
set.add('a');
set.add('e');
set.add('i');
set.add('o');
set.add('u');
int res=0;
int count=0;
//前k个元素遍历完
for(int i= 0;i < k; i++){
char temp =s.charAt(i);
if(set.contains(temp)){
count++;
}
}
res=Math.max(res,count);
for(int i = k;i < s.length(); i++){
char right=s.charAt(i);
char left=s.charAt(i-k);
if(set.contains(right)){
count++;
}
if(set.contains(left)){
count--;
}
res=Math.max(res,count);
}
return res;
}
class Solution {
public int maxVowels(String s, int k) {
int left = 0;
int count = 0;
int result = 0;
for (int right = 0; right < s.length(); right++) {
char rightChar = s.charAt(right);
if (right < k) {
if (isVowel(rightChar)) {
count++;
}
result = count;
} else {
if (isVowel(rightChar)) {
count++;
}
char leftChar = s.charAt(left);
if (isVowel(leftChar)) {
count--;
}
result = Math.max(result, count);
left++;
}
}
return result;
}
private boolean isVowel(char c) {
return c == 'a' || c == 'o' || c == 'e' || c == 'i' || c == 'u';
}
}
两种方法都是先看 前k个元素中元音的个数
然后窗口向右移动,如果左边是元音,-1,如果右边是,+1