秋招-算法-滑动窗口篇
介绍
滑动窗口是双指针的一种特例,可以称为左右指针,在任意时刻,只有一个指针运动,而另一个保持静止。滑动窗口路一般用于解决特定的序列中符合条件的连续的子序列的问题。
滑动窗口的时间复杂度是线性的,一般为O ( n ),滑动窗口是一种全遍历问题,一定会遍历到末尾的。
其本质思路在于:
- 初始化将滑动窗口压满,取得第一个滑动窗口的目标值
- 继续滑动窗口,每往前滑动一次,需要删除一个和添加一个元素,求最优的目标值
模板
int left = 0, right = 0;
while (right < s.size()) {
// 增大窗口,对右侧元素进行操作
int rightNum = nums[right];
rightNumxxx ;
right++;
while (window needs shrink) {
// 缩小窗口
// 移除左侧元素
int leftNum = nums[left];
leftNumxxx ;
left++;
}
}
例题
定窗口滑动问题
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left=0,right = 0;
int sum = 0;
int res = Integer.MAX_VALUE;
while (right<nums.length){
int rightNum = nums[right];
sum+=rightNum;
while (sum>=target){
res = Math.min(right - left +1, res);
sum-=nums[left++];
}
right++;
}
if (res == Integer.MAX_VALUE){
return 0;
}
return res;
}
}
class Solution {
public boolean checkInclusion(String s1, String s2) {
if (s2.length()<s1.length()) return false;
HashMap<Character,Integer> sourceMemo = new HashMap<>();
HashMap<Character,Integer> targetMemo = new HashMap<>();
int left,right;
for (int i = 0; i < s1.length(); i++) {
targetMemo.put(s1.charAt(i),targetMemo.getOrDefault(s1.charAt(i),0)+1);
sourceMemo.put(s2.charAt(i),sourceMemo.getOrDefault(s2.charAt(i),0)+1);
}
sourceMemo.put(s2.charAt(s1.length()-1),sourceMemo.getOrDefault(s2.charAt(s1.length()-1),0)-1);
for (left=0,right = s1.length()-1; right < s2.length(); right++,left++) {
sourceMemo.put(s2.charAt(right),sourceMemo.getOrDefault(s2.charAt(right),0)+1);
if (left!=0)
sourceMemo.put(s2.charAt(left-1),sourceMemo.getOrDefault(s2.charAt(left-1),0)+-1);
if (findEqual(sourceMemo,targetMemo)){
return true;
}
}
return false;
}
private boolean findEqual(HashMap<Character, Integer> sourceMemo, HashMap<Character, Integer> targetMemo) {
Set<Character> characters = targetMemo.keySet();
for (Character key : characters) {
if (targetMemo.get(key)>(sourceMemo.getOrDefault(key,0))){
return false;
}
}
return true;
}
}
不定窗口滑动问题
class Solution {
public String minWindow(String s, String t) {
String res = "";
int minLen=Integer.MAX_VALUE;
HashMap<Character,Integer> sourceMemo = new HashMap<>();
HashMap<Character,Integer> targetMemo = new HashMap<>();
int left=0,right = 0;
for (int i = 'A'; i <= 'Z'; i++) {
sourceMemo.put((char) i,0);
targetMemo.put((char) i,0);
}
for (int i = 'a'; i <= 'z'; i++) {
sourceMemo.put((char) i,0);
targetMemo.put((char) i,0);
}
for (int i = 0; i < t.length(); i++) {
mapPlus(targetMemo,t.charAt(i));
}
while (right<s.length()){
char now = s.charAt(right);
mapPlus(sourceMemo,now);
if (findEqual(sourceMemo,targetMemo)){
char old = s.charAt(left);
while (findEqual(sourceMemo,targetMemo)) {
old = s.charAt(left);
mapSub(sourceMemo, old);
left++;
}
left--;
mapPlus(sourceMemo, old);
if (minLen>right-left){
minLen = right-left;
res = s.substring(left,right+1);
}
}
right++;
}
return res;
}
private boolean findEqual(HashMap<Character, Integer> sourceMemo, HashMap<Character, Integer> targetMemo) {
for (Character key : targetMemo.keySet()) {
if (targetMemo.get(key)==0) continue;
if (targetMemo.get(key)>(sourceMemo.get(key))){
return false;
}
}
return true;
}
void mapPlus(HashMap<Character,Integer> map,Character target){
map.put(target,map.get(target)+1);
}
void mapSub(HashMap<Character,Integer> map,Character target){
map.put(target,map.get(target)-1);
}
}