分类:窗口有两类,一种是固定大小类的窗口,一类是大小动态变化的窗口。
应用:什么情况可以用滑动窗口来解决实际问题呢?
- 一般给出的数据结构是数组或者字符串
- 求取某个子串或者子序列最长最短等最值问题或者求某个目标值时(子序列也有可能是动态规划的解法所以要区分,动态规划求子序列基本是求几种方法/最长长度)
- 该问题本身可以通过暴力求解
209、长度最小的子数组
给定一个含有 n
个正整数的数组和一个正整数 target
。找出该数组中满足其和 ≥ target
的长度最小的 连续子数组 [numsl,numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
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){
sum+=nums[right];
right++;
while(sum>=target){
res=Math.min(res,right-left);
sum-=nums[left];
left++;
}
}
return res==Integer.MAX_VALUE?0:res;
}
}
438、找到字符串中所有字母异位词 (比其他题要有相对复杂的细节考虑)
给定两个字符串 s
和 p
,找到 s
中所有 p
的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
重要的细节都在代码注释上了
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer>list=new ArrayList<>();
Map<Character,Integer>map=new HashMap<>();
Map<Character,Integer>window=new HashMap<>();
char ch[]= p.toCharArray();
//p的各个字符的次数记录
for(char c:ch){
map.put(c,map.getOrDefault(c,0)+1);
}
int left=0,right=0;
int sum=0;//记录每一个字母的个数
while(right<s.length()){
char c=s.charAt(right);
right++;
if (map.containsKey(c)) {//map只添加跟异位词有关的字符,不添加其他的
window.put(c, window.getOrDefault(c, 0) + 1);
// 不能写== 比较的是两个地址!!!(就无脑用equals吧)
if (map.get(c).equals(window.get(c))) {
sum++;
}
}
while ((right - left) >= p.length()) {
if (sum == map.size()) {
//注意这里是sum==map.size()而不是sum==p.length()
//s="baa"
//p="aa"
list.add(left);//进行操作
}
char temp = s.charAt(left);
left++;//收缩窗口
if (map.containsKey(temp)) {
//s=cba p=cc 输出是0——>要有如下if的判断,sum才--
if (map.get(temp).equals(window.get(temp))) {
sum--;
}
window.put(temp, window.getOrDefault(temp, 0) - 1);
}
}
}
return list;
}
}
1208、尽可能使字符串相等
给你两个长度相同的字符串,s
和 t
。将 s
中的第 i
个字符变到 t
中的第 i
个字符需要 |s[i] - t[i]|
开销(开销可能为 0),也就是两个字符的 ASCII 码值的差的绝对值。
用于变更字符串的最大预算是 maxCost
。在转化字符串时,总开销应当小于等于该预算,这也意味着字符串的转化可能是不完全的。如果你可以将 s
的子字符串转化为它在 t
中对应的子字符串,则返回可以转化的最大长度。如果 s
中没有子字符串可以转化成 t
中对应的子字符串,则返回 0
。
class Solution {
public int equalSubstring(String s, String t, int maxCost) {
int left=0,right=0;
int sum=0;//记录转化字符的总开销
int res=0;
while(right<s.length()){
sum+=Math.abs(s.charAt(right)-t.charAt(right));
right++;
while(sum>maxCost){
sum-=Math.abs(s.charAt(left)-t.charAt(left));
left++;
}
//转化后的最大长度
res=Math.max(res,right-left);
}
return res;
}
}
1456、定长子串中元音的最大数目
给你字符串 s
和整数 k
。请返回字符串 s
中长度为 k
的单个子字符串中可能包含的最大元音字母数。英文中的 元音字母 为(a
, e
, i
, o
, u
)。
class Solution {
public int maxVowels(String s, int k) {
int left=0,right=0;
int sum=0;//记录元音字母的个数
int res=0;
while(right<s.length()){
sum+=isVowel(s.charAt(right));
right++;
while((right-left)>=k){
//当窗口长度≥k,则计算此时的子字符串的最大元音字母
res=Math.max(res,sum);
sum-=isVowel(s.charAt(left));
left++;
}
}
return res;
}
//判断是否是元音字母
public int isVowel(char ch) {
return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' ? 1 : 0;
}
}