该类题型模板:外层都是以右边界为对象进行移动,右边界每移动一次,对左边界进行移动和分析,并且检查结果是否需要更新(调用Math.max/min()函数);
模板其实都是一样的,可能会加入其他考点如哈希表的使用等等;
209.长度最小的子数组
题目链接
这里的时间复杂度,只需要看指针们的移动量,因为左右指针最多移动n次,即2n,复杂度为O(n)
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int ans=Integer.MAX_VALUE;
int start=0;int end=0;int sum=0;
while(end<nums.length){
sum+=nums[end];
while(sum>=target){
ans=Math.min(ans, end-start+1);
sum-=nums[start++];
}
end++;//放哪里?????——其始终指向sum序列中的首元素和末尾元素
}
return ans==Integer.MAX_VALUE ? 0:ans;
}
}
904.水果成篮
题目链接
说人话其实就是找最长的含有两个元素的字符串(数组);
个人过不来的点:不知道如何快速找出一个字符串是否有两个元素:使用哈希表;
class Solution {
public int totalFruit(int[] fruits) {
int ans=Integer.MIN_VALUE;
int start=0;int end=0;
Map<Integer, Integer> cnt=new HashMap<Integer, Integer>();
//该哈希表左侧是水果种类序号,右侧是该种水果出现的次数
for(; end<fruits.length; end++){//end
cnt.put(fruits[end], cnt.getOrDefault(fruits[end], 0)+1);
while(cnt.size()>2){
cnt.put(fruits[start], cnt.get(fruits[start])-1);
if(cnt.get(fruits[start])==0){
cnt.remove(fruits[start]);
}
start++;
}
ans=Math.max(ans, end-start+1);
}
return ans==Integer.MIN_VALUE?0:ans;
}
}
76.最小覆盖子串
Tips
这里我发现一个很好用的刷题方法
当刷完前两道题,基本已经对滑动窗口的模板有了大致了解,在刷其他题目同题型题目时,可以先写出思路(伪代码),然后写下自己当时过不来的点,再看题解,看看别人是怎么做的:
比如这道题,我就是不知道右边界移动起来如何体现(如何收缩窗口)
看了力扣的官方题解视频后,使用的他的思路:
class Solution {
public String minWindow(String s, String t) {
//结果所需变量
int begin=0,length=s.length()+1;
//原始字符串转换为数组
char[] ss=s.toCharArray();
char[] tt=t.toCharArray();
//准备频率数组
int sarr_num[]=new int[128];
int tarr_num[]=new int[128];
for(int i=0; i<tt.length; i++){
tarr_num[tt[i]]++;
}
//[left, right)
int left=0,right=0;
int distance=0;//similar like海明距
//开始挪动右边界
while(right<ss.length){
if(tarr_num[ss[right]]==0){
right++;
continue;
}
if(sarr_num[ss[right]]<tarr_num[ss[right]]){
distance++;
}
sarr_num[ss[right]]++;
right++;
//左边界的移动
while(distance==tt.length){
if(right-left<length){
begin=left;
length=right-left;
}
if(tarr_num[ss[left]]==0){
left++;
continue;
}
if(sarr_num[ss[left]]==tarr_num[ss[left]]){
distance--;
}
sarr_num[ss[left]]--;
left++;
}
}
//返回元素,不要忘记不存在的情况
if(length==ss.length+1) return "";
else return s.substring(begin, begin+length);
}
}
三道滑动窗口,其实都是一个模板
三道题不同之处在于:
第一道题直接套用,没有其他考点
第二道题考到了哈希表
第三道题考到了哈希表的变式:ASCII码只有128个,所以只需要一个长度为128的数组来作为桶排序的“桶名”
(不准确,但差不多这个意思)另外,还需要注意第三题数组可以乱序,可以出现多次,都需要体现在算法中,这也是选择哈希数组的原因(因为Java自带的HashMap只能记录键值和实际值,无法记录出现次数)