滑动窗口是双指针技巧的一种,常用于解决子串、子序列问题。滑动窗口的思想是维护一个窗口,不断滑动更新。滑动窗口的难点是各种细节:如何向窗口中添加元素、如何缩小窗口、何时更新结果。
滑动窗口有一套通用的框架,解决滑动窗口题目大家都可以尝试套用该框架。框架的整体思路是移动窗口右边界,向窗口中添加元素,窗口满足要求解的问题(如窗口等于目标子串),开始滑动左边界找到满足条件的最小值。
图来自【2】(参考来源)
public void slidingWindow(String str,String target){
//用哈希表存储当前窗口中每个字符出现次数
// need:存储待查找子串每个字符出现次数
Map need,window = new HashMap();
//窗口左右边界
int left = 0;
int right = 0;
while(right
left和right分别负责滑动窗口的左右边界,那么有时这个窗口是固定的,有时则是不固定长度,会需要求最小长度。
基本在窗口内,right是每轮都需要++的,可以通过continue提前跳过本轮,减少一丢时间
在达到一定的条件后就需要收缩窗口了,若是固定窗口长度,泽到达固定长度后收缩,若是求最小长度,则一直收缩到窗口内的值不满足条件为止
res最后的返回答案,可以在每轮right++后进行更新,也可以在left++后更新,那么有时最后一轮right 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 输入: s = "pwwkew" Boolean数组 HashMap int数组 本题小结:(1)注意在最后还有一次比较 (2)对于伪HashSet可以用boolean数组代替 (3)一般达到条件后left左移都是用while循环,达到一个条件后退出 给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。 输入: s = "cbaebabacd", p = "abc" 本题小结:(1)注意边界位置right - left +1 给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。 换句话说,s1 的排列之一是 s2 的 子串 。 输入:s1 = "ab" s2 = "eidbaooo" 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。 输入:s = "ADOBECODEBANC", t = "ABC" 本题小结:(1)以count来记录在滑动窗口内有效字符串个数,对其他无效的不给记录 给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 i 和 j ,满足 nums[i] == nums[j] 且 abs(i - j) <= k 。如果存在,返回 true ;否则,返回 false 。 输入:nums = [1,2,3,1], k = 3 HashSet 本题小结:(1)以HashSet的长度充当k的长度,大大简化空间和时间。 给你一个整数数组 nums 和两个整数 k 和 t 。请你判断是否存在 两个不同下标 i 和 j,使得 abs(nums[i] - nums[j]) <= t ,同时又满足 abs(i - j) <= k 。 如果存在则返回 true,不存在返回 false。 输入:nums = [1,2,3,1], k = 3, t = 0 本题小结:(1)最后会出现大数,要用long,并且要判断null,所以注意Long (2)ceiling返回大于等于那个数的最小数 (3)开始的ceiling要减去t (4)remove去除的元素是最左边的那个,for循环去除即可 参考来源:【1】leetcode 滑动窗口 【2】CSDN 惊鸿只为卿 滑动窗口详解 【3】leetcode 官方题解 存在重复元素 III三. leetcode实战
1. leetcode3 无重复字符的最长子串
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。class Solution {
public int lengthOfLongestSubstring(String s) {
if(s == null){
return 0;
}
boolean[] arr = new boolean[128];
char[] ch = s.toCharArray();
int left = 0;
int right = 0;
int dis = 0;
int max =0;
while(right < ch.length){
if(arr[ch[right]] == false){
arr[ch[right]] = true;
right++;
continue;
}
dis = right-left;
max = max > dis? max : dis;
while(arr[ch[right]] == true){
arr[ch[left]] = false;
left++;
}
}
dis = right-left;
max = max > dis? max : dis;
return max;
}
}
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s == null || s.length() == 0){
return 0;
}
HashMap
class Solution {
public int lengthOfLongestSubstring(String s) {
int left = 0;
int right = 0;
int diff = 0;
int max = 0;
int len = s.length();
int[] nums = new int[256];
while(right < len){
if(nums[s.charAt(right)] == 0){
nums[s.charAt(right)]++;
right++;
continue;
}
diff = right-left;
max = Math.max(max, diff);
while(nums[s.charAt(right)] > 0){
nums[s.charAt(left)]--;
left++;
}
}
diff = right-left;
max = Math.max(max, diff);
return max;
}
}
2. leetcode438 找到字符串中所有字母异位词
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。 class Solution {
public List
3. leetcode567 字符串的排列
输出:true
解释:s2 包含 s1 的排列之一 ("ba").class Solution {
public boolean checkInclusion(String s1, String s2) {
if(s1.length() > s2.length()) return false;
int[] oristr = new int[26];
int[] win = new int[26];
int left = 0;
int right = 0;
for(int i = 0; i < s1.length(); i++){
oristr[s1.charAt(i)-'a']++;
}
while(right < s2.length()){
char c1 = s2.charAt(right);
win[c1 -'a']++;
while( win[c1 -'a'] > oristr[c1 -'a']){
char c2 = s2.charAt(left);
win[c2-'a']--;
left++;
}
if( right - left +1== s1.length()){
return true;
}
right++;
}
return false;
}
}
4. leetcode76 最小覆盖子串
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。
输出:"BANC"class Solution {
public String minWindow(String s, String t) {
if(s.length() < t.length()) return "";
int[] ori = new int[128];
int[] win = new int[128];
int right = 0;
int left = 0;
int res = s.length();
int count = 0;
String str = "";
for(int i = 0; i < t.length(); i++){
ori[t.charAt(i)]++;
}
while(right < s.length()){
char c = s.charAt(right);
win[c]++;
if(ori[c] >0 && win[c] <= ori[c]){
count++;
}
while(count == t.length()){
char cL = s.charAt(left);
if(ori[cL] > 0 && win[cL] <= ori[cL]){
count--;
}
if(right-left+1 <= res){
res = right-left+1;
str = s.substring(left,right+1);
}
left++;
win[cL]--;
}
right++;
}
return str;
}
}
5. leetcode219 存在重复元素 II
输出:true
HashMapclass Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
HashMap
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
HashSet
6. leetcode220 存在重复元素 III
输出:true
class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
TreeSet