Java滑动窗口实现详解
滑动窗口是一种常用的算法技巧,主要解决连续子数组/子字符串问题,以下是几种常见实现方式:

固定长度滑动窗口
public class FixedSlidingWindow {
// 示例:计算长度为k的子数组最大和
public static int maxSumWindow(int[] nums, int k) {
if (nums == null || nums.length < k) {
return 0;
}
// 计算第一个窗口的和
int windowSum = 0;
for (int i = 0; i < k; i++) {
windowSum += nums[i];
}
int maxSum = windowSum;
// 滑动窗口
for (int i = k; i < nums.length; i++) {
windowSum += nums[i] - nums[i - k]; // 加入新元素,移除旧元素
maxSum = Math.max(maxSum, windowSum);
}
return maxSum;
}
public static void main(String[] args) {
int[] nums = {1, 4, 2, 10, 23, 3, 1, 0, 20};
int k = 4;
System.out.println("最大和为: " + maxSumWindow(nums, k)); // 输出: 39
}
}
可变长度滑动窗口
public class VariableSlidingWindow {
// 示例:找出和大于等于target的最短子数组长度
public static int minSubArrayLen(int target, int[] nums) {
int left = 0;
int sum = 0;
int minLen = Integer.MAX_VALUE;
for (int right = 0; right < nums.length; right++) {
sum += nums[right]; // 扩展窗口
// 收缩窗口
while (sum >= target) {
minLen = Math.min(minLen, right - left + 1);
sum -= nums[left];
left++;
}
}
return minLen == Integer.MAX_VALUE ? 0 : minLen;
}
public static void main(String[] args) {
int[] nums = {2, 3, 1, 2, 4, 3};
int target = 7;
System.out.println("最短子数组长度: " + minSubArrayLen(target, nums)); // 输出: 2
}
}
字符串滑动窗口通用模板
public class StringSlidingWindow {
// 通用模板:查找最长无重复字符子串
public static int lengthOfLongestSubstring(String s) {
if (s == null || s.length() == 0) return 0;
int left = 0;
int maxLen = 0;
Map<Character, Integer> charMap = new HashMap<>();
for (int right = 0; right < s.length(); right++) {
char c = s.charAt(right);
// 如果字符已出现,移动左边界
if (charMap.containsKey(c) && charMap.get(c) >= left) {
left = charMap.get(c) + 1;
}
// 更新字符位置
charMap.put(c, right);
// 计算当前窗口长度
maxLen = Math.max(maxLen, right - left + 1);
}
return maxLen;
}
public static void main(String[] args) {
String s = "abcabcbb";
System.out.println("最长无重复子串长度: " + lengthOfLongestSubstring(s)); // 输出: 3
}
}
通用滑动窗口框架
public class SlidingWindowFramework {
// 滑动窗口通用模板
public static List<Integer> slidingWindowTemplate(int[] nums) {
List<Integer> result = new ArrayList<>();
if (nums == null || nums.length == 0) return result;
int left = 0, right = 0;
// 维护窗口状态的变量
int windowSum = 0;
int maxSum = Integer.MIN_VALUE;
while (right < nums.length) {
// 1. 扩展窗口:加入右边元素
int num = nums[right];
windowSum += num;
// 2. 根据条件收缩窗口
// 窗口长度固定为k
while (right - left + 1 > 3) { // 假设窗口最大长度为3
windowSum -= nums[left];
left++;
}
// 3. 更新结果
if (right - left + 1 == 3) {
maxSum = Math.max(maxSum, windowSum);
}
// 4. 继续移动右指针
right++;
}
result.add(maxSum);
return result;
}
}
实际应用示例:最小覆盖子串
public class MinWindowSubstring {
// 找出包含目标字符串所有字符的最小子串
public static String minWindow(String s, String t) {
if (s == null || t == null || s.length() < t.length()) {
return "";
}
Map<Character, Integer> need = new HashMap<>();
Map<Character, Integer> window = new HashMap<>();
// 初始化需要字符的计数
for (char c : t.toCharArray()) {
need.put(c, need.getOrDefault(c, 0) + 1);
}
int left = 0, right = 0;
int valid = 0; // 满足条件的字符数
int start = 0; // 记录最小子串起始位置
int len = Integer.MAX_VALUE; // 记录最小子串长度
while (right < s.length()) {
char c = s.charAt(right);
right++;
// 更新窗口内数据
if (need.containsKey(c)) {
window.put(c, window.getOrDefault(c, 0) + 1);
if (window.get(c).equals(need.get(c))) {
valid++;
}
}
// 判断是否要收缩窗口
while (valid == need.size()) {
// 更新最小子串
if (right - left < len) {
start = left;
len = right - left;
}
char d = s.charAt(left);
left++;
// 更新窗口内数据
if (need.containsKey(d)) {
if (window.get(d).equals(need.get(d))) {
valid--;
}
window.put(d, window.get(d) - 1);
}
}
}
return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len);
}
public static void main(String[] args) {
String s = "ADOBECODEBANC";
String t = "ABC";
System.out.println("最小覆盖子串: " + minWindow(s, t)); // 输出: "BANC"
}
}
- 固定窗口:left和right同步移动,每次加入新元素并删除旧元素
- 可变窗口:right不断右移,当条件满足时左移left
- 关键变量:
- left/right:窗口边界
- window:窗口内数据状态
- valid:满足条件的计数
- result:记录最终结果
选择哪种实现取决于具体需求:固定长度问题用第一种,可变长度用第二种,字符串匹配用第三种。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播