滑动窗口主要用来处理连续问题。比如题目求解“连续子串 xxxx”,“连续子数组 xxxx”,就应该可以想到滑动窗口。能不能解决另说,但是这种敏感性还是要有的。
从类型上说主要有:
- 固定窗口大小
- 窗口大小不固定,求解最大的满足条件的窗口
- 窗口大小不固定,求解最小的满足条件的窗口(上面的 209 题就属于这种)
后面两种我们统称为可变窗口
。当然不管是哪种类型基本的思路都是一样的,不一样的仅仅是代码细节。
固定窗口大小
对于固定窗口,我们只需要固定初始化左右指针 l 和 r,分别表示的窗口的左右顶点,并且保证:
- l 初始化为 0
- 初始化 r,使得 r - l + 1 等于窗口大小
- 同时移动 l 和 r
- 判断窗口内的连续元素是否满足题目限定的条件
- 4.1 如果满足,再判断是否需要更新最优解,如果需要则更新最优解
- 4.2 如果不满足,则继续。
可变窗口大小
对于可变窗口,我们同样固定初始化左右指针 l 和 r,分别表示的窗口的左右顶点。后面有所不同,我们需要保证:
- l 和 r 都初始化为 0
- r 指针移动一步
- 判断窗口内的连续元素是否满足题目限定的条件
- 3.1 如果满足,再判断是否需要更新最优解,如果需要则更新最优解。并尝试通过移动 l 指针缩小窗口大小。循环执行 3.1
- 3.2 如果不满足,则继续。
形象地来看的话,就是 r 指针不停向右移动,l 指针仅仅在窗口满足条件之后才会移动,起到窗口收缩的效果。
Leetcode 3.无重复字符的最长子串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { public int lengthOfLongestSubstring(String s) { int r = 0; int l = 0; int max =0; HashMap<Character, Integer> map = new HashMap<Character, Integer>(); for(r = 0;r<s.length();r++) { if(map.containsKey(s.charAt(r))) l = Math.max(l,map.get(s.charAt(r)) + 1); map.put(s.charAt(r),r); max = Math.max(max,r-l+1); } return max; } }
|
Leetcode 76.最小覆盖子串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Solution { public String minWindow(String s, String t) { if (s == null || s == "" || t == null || t == "" || s.length() < t.length()) { return ""; } int t_length=t.length(); char[] chars = s.toCharArray(), chart = t.toCharArray(); int[] hold = new int[128]; for(int i = 0;i<t_length;i++) { char temp=chart[i]; hold[temp]--; } String output=""; int right=0; int left=0; int count=0; for(right=0;right<s.length();right++) { hold[chars[right]]++; if(hold[chars[right]]<=0)count++; while(count==t_length&&hold[chars[left]]>0) { hold[chars[left]]--; left++; } if(count==t_length) if(output==""||output.length()>right-left+1) output=s.substring(left,right+1); } return output; } }
|
Leetcode 209.长度最小的子数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Solution { public int minSubArrayLen(int target, int[] nums) { int right=0; int left=0; int num=0; int count=0; for(right=0;right<nums.length;right++) { num+=nums[right]; while(num>=target) { if(count==0||count>right-left+1) count=right-left+1; num-=nums[left]; left++; } } return count; } }
|