数组和滑动窗口。滑动窗口这块也是数组里面比较常用的一个技巧,通常用法就是在数组里面找一个子序列,下面就通过几道题来了解滑动窗口的用法。题目还是在这个链接里面。
LeedCode209
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
提示:
这道题我们可以使用滑动窗口来解欸,滑动窗口使用一个L指针,一个R指针,维护一个窗口,下面来图解看看这道题。首先说一下思路,首先把窗口里面的值的总和叫做 sum, 目标值 = target, 当 sum < target 的时候,R指针往右扩充,L不变,窗口变大, sum 也在不断变大,当 sum >= target 的时候, L 往右移动并且 sum 减少,当 sum == target 的时候记录下来,然后等到 sum < target 的时候,再移动右指针。
2、R 一直移动,移动到 L ~ R 范围内的数字总和 >= 7
3、L开始向右移动,每移动一次判断是否达到条件,并且判断 sum 是否 < target,如果在图中等于 target,那么记录下来 min = R-L+1, 长度
4、继续重复当 sum > target 的时候L++,R不变
5、操作 L++,并不断查找sum是否等于target,如果等于,那么记录下来 min = Math.min(min, R-L+1)
8、L++, 此时 sum = 3 < 7,R++,R越界,结束,返回结果 min = 2
class Solution {
public int minSubArrayLen(int target, int[] nums) {
//滑动窗口
int L = 0;
int R = 0;
int sum = 0;
//min是返回的结果
int min = Integer.MAX_VALUE;
while(R < nums.length){
//每一次R++,sum += nums[R]
sum += nums[R];
while(sum >= target){
//当sum >= target的时候,L++, R不变
min = Math.min(min, R-L+1);
//L移动一次sum就减少一个
sum -= nums[L];
L++;
}
R++;
}
//如果min == MAX_VALUE,那么证明全程都没有等于target的子序列,返回0
return min == Integer.MAX_VALUE ? 0 : min;
}
}
LeedCode904: 水果成篮
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
示例 1:
输入:fruits = [1,2,1]
输出:3
解释:可以采摘全部 3 棵树。
示例 2:
输入:fruits = [0,1,2,2]
输出:3
解释:可以采摘 [1,2,2] 这三棵树。
如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。
示例 3:
输入:fruits = [1,2,3,2,2]
输出:4
解释:可以采摘 [2,3,2,2] 这四棵树。
如果从第一棵树开始采摘,则只能采摘 [1,2] 这两棵树。
示例 4:
输入:fruits = [3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:可以采摘 [1,2,1,1,2] 这五棵树。
提示:
题目说人话就是在一个数组中找到两个数字的最大子序列,比如 1,2,3,2,2就是4,因为最大子序列是2和3这两个数,这两个数出现了四次2,3,2,2.又比如 [3,3,3,1,2,1,1,2,3,3,4],最大就是5,是1和2这两个数,出现了5次,1,1,2,3,3。
解题思路就是滑动窗口,R++的时候记录下来水果的种类的数量,如果大于2,那么L++,否则R++。有兴趣可以自己画图试一下,这里就不给出图了。下面注释写得很清楚了。
class Solution {
/**
题目的意思就是给你一个数组, 你要在里面找到只包含两个数的最大子序列
比如 1,2,3,2,2就是4, 因为2,3,2,2只包含2和3, 且是最长的
*/
public int totalFruit(int[] fruits) {
//使用滑动窗口
int L = 0;
int R = 0;
int count = 0; //count记录现在L-R之间的水果种类有多少
int ans = 2; //结果, 初始设置为2,结果肯定>=2的
int[] res = new int[fruits.length]; //记录水果种数的数组, 0 <= fruits[i] < fruits.length作为限制不用担心内存爆栈的问题
int len = fruits.length;
if(len < 2){
return len; //长度小于2的就直接返回长度就可以了
}
while(R < len){
//对应下标++
res[fruits[R]]++;
//如果对应下标是1的话, count+1表示找到一种不同类型的水果
if(res[fruits[R]] == 1){
count++;
}
//判断此时count有没有超过2了, 如果超过了左指针就要往右移动
while(count > 2){
res[fruits[L]]--;
if(res[fruits[L]] == 0){
count--;
}
L++;
}
ans = Math.max(ans, R-L+1);
R++;
}
return ans;
}
}
LeedCode76: 最小覆盖子串
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
注意:
示例 1:
输入:s = “ADOBECODEBANC”, t = “ABC”
输出:“BANC”
示例 2:
输入:s = “a”, t = “a”
输出:“a”
示例 3:
输入: s = “a”, t = “aa”
输出: “”
解释: t 中两个字符 ‘a’ 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串
提示:
使用 size 和 start 记录字符串的开始位置和长度,使用滑动窗口 L 和 R,首先遍历一次 t,用一个 int 数组 result 记录下来 t 的每个字符的数量。然后滑动窗口遍历 s ,每次 R++ 的时候 result 对应的字符–,然后检测,左边字符++,对应 result 下标 ++,每一次都判断最大值和最大长度。最终返回。
class Solution {
public String minWindow(String s, String t) {
//滑动窗口,字符数组
if(s == null || s.length() == 0 || t == null || t.length() == 0){
return "";
}
int[] need = new int[128];
//记录t的字符数
for(int i = 0; i < t.length(); i++){
need[t.charAt(i)] ++;
}
//左边界,右边界,size窗口大小,count是需求的字符个数,start是最小覆盖串开始的index
int L = 0, R = 0, size = Integer.MAX_VALUE, count = t.length(), start = 0;
//滑动窗口
/**
思路:首先R往右等到包含了t的所有字符
然后此时L往右移动到第一个包含t的字符串的位置, 然后往右移动一格
最后R再次往右移动
*/
while(R < s.length()){
char c = s.charAt(R);
if(need[c] > 0){
//此时c是需要的字符
count --;
}
need[c]--; //如果死是不需要的字符,最后变成负数
if(count == 0){ //count=0表示找到了所有t中的字符
//1、往左开始遍历去除不是必要的字符
while(L < R && need[s.charAt(L)] < 0){
need[s.charAt(L)] ++; //释放空间,恢复++
L++; //左指针往右移动
}
//找到了第一个要去除的必要字符
if(R -L + 1 < size){ //此时的窗口比原来的要小
size = R - L + 1;
start = L; //start记录下标
}
//下面去除第一个必要字符
need[s.charAt(L)] ++;
L ++;
count++; //去除了一个, 就要后面R++的时候补回来
}
R++;
}
//最后判断如果是Integer.MAX_VALUE就证明了一直没有更新, 根本找不到
return size == Integer.MAX_VALUE? "" : s.substring(start, start + size);
}
}
如有错误,欢迎指出!!!!