滑动窗口
209-Minimum Size Subarray Sum (对于滑动窗口(队列)和对撞指针的相似之处的理解)
给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组
1,大顶堆选出最大的数,依次弹出相加与target比较,循环条件是和小于target
2,数组中的元素不停的入队,直到总和大于等于 s 为止,接着记录下队列中元素的个数,然后再不停的出队,直到队列中元素的和小于 s 为止(如果不小于 s,也要记录下队列中元素的个数,这个个数其实就是不小于 s 的连续子数组长度,我们要记录最小的即可)。接着再把数组中的元素添加到队列中……重复上面的操作,直到数组中的元素全部使用完为止。使用指针实现队列
public static int minSubArrayLen(int s,int[] nums) {
int lo=0,hi=0,sum=0,min=Integer.MAX_VALUE;//
while(hi<nums.length) {
//hi指针记录了数组放入队列的次数,lo指针记录了数组弹出的次数
sum+=nums[hi++];
while(sum>=s) {
min=Math.min(min, hi-lo);//hi-lo是队列中数的数量
sum-=nums[lo++];
}
}
return min==Integer.MAX_VALUE?0:min;
}
3,二分法查找,用数组sums[i]表示的是原数组nums前i个元素的和,题中说了“给定一个含有n个正整数的数组”,所以sums数组中的元素是递增的。找到sums[k]-sums[j]>=s,即sums[j]+s<=sums[k],因为元素递增,我们只需要求出sum[j]+s的值,使用二分法查找即可找到这个k。
4,直接使用窗口,每次往窗口添加元素来判断是否满足。先固定一个窗口大小length,遍历数组,查看在数组中length个元素长度的和是否有满足的,没有就扩大窗口,有就记录下来缩小窗口的大小length继续找。
public static int minSubArrayLen(int s,int[] nums) {
int lo=1,hi=nums.length,min=0;
while(lo<=hi) {
int mid=(lo+hi)>>1;//除以2的n次方
if(windowExist(mid,nums,s)) {
hi=mid-1;//找到就缩小窗口的大小
min=mid;//记录窗口最小值
}else
lo=min+1;//没找到就扩大窗口的大小
}
return min;
}
private static boolean windowExist(int size,int[] nums,int s) {
int sum=0;
for(int i=0;i<nums.length;i++) {
//从第i位开始往后加,加到限制大小还没有找到就找i+1,最后还没找到返回false
if(i>=size)
sum-=nums[i-size];
sum+=nums[i];
if(sum>=s)
return true;
}
return false;
}
3-Longest Substring Without Repeating Characters
给定一个字符串,找出其中不含有重复字符的 最长子串 的长度。 输入: s = “pwwkew” 输出: 3 解释:
因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串,s由英文字母,数字,符号和空格组成。
依然是滑动窗口,即队列。
public int lengthOfLongerstSubstring(String s) {
if(s.length()==0)return 0;
//这里要用HashMap是因为,重复的元素不一定出现在左顶端
HashMap<Character,Integer>map=new HashMap<Character,Integer>();
int max=0;
int left=0;
for(int i=0;i<s.length();i++) {
if(map.containsKey(s.charAt(i))) {
left=Math.max(left, map.get(s.charAt(i))+1);
//把队列左边的重复元素移除,如果重复元素在最左端的右边就去除元素的左边所有元素
//移除其实就是移动指针指向的位置
}
map.put(s.charAt(i), i);//继续向map中添加元素
max=Math.max(max, i-left+1);//更新窗口大小
}
return max;
}
340-Longest Substring with At Most K Distinct Characters
给定一个字符串 s ,找出 至多 包含 k 个不同字符的最长子串 T。
示例 :
输入: s = “eceba”, k = 2 输出: 3 解释: 则 T 为 “ece”,所以长度为 3。 示例 2:
输入: s = “aa”, k = 1 输出: 2 解释: 则 T 为 “aa”,所以长度为 2。
滑动窗口,初始时左右指针都指向0,用一个HashMap循环记录字符及频率,当不同字符数量过多,将左端字符取出,