解题技巧:定长滑窗问题
定长滑窗问题通常可以通过以下步骤解决:
初始化窗口统计量
定义一个变量来记录窗口内的统计量(如和、计数等)。 初始化窗口的统计量,通常是前 k
个元素的统计值。 滑动窗口遍历数组
使用一个循环,从第 k
个元素开始遍历数组。 在每次迭代中,执行以下三步操作:入 :将当前元素加入窗口,更新统计量。更新 :根据当前窗口的统计量,更新答案(如最大值、最小值、计数等)。出 :移除窗口左端的元素,更新统计量。 边界条件处理
确保数组长度大于或等于窗口大小 k
。 根据题目要求,处理特殊情况(如空数组、无解等)。 优化
使用滑窗技术避免重复计算,确保时间复杂度为 O(n)
。 模板代码 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public int solveSlidingWindow (int [] nums, int k) { int n = nums.length; int result = 0 ; int windowSum = 0 ; for (int i = 0 ; i < k; i++) { windowSum += nums[i]; } result = Math.max(result, windowSum); for (int i = k; i < n; i++) { windowSum += nums[i]; windowSum -= nums[i - k]; result = Math.max(result, windowSum); } return result; }
适用场景 :
求定长子数组的最大/最小值。 统计满足条件的定长子数组个数。 计算定长子数组的平均值或其他统计量。 通过掌握滑窗的“入-更新-出”三步法,可以高效解决这类问题。
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 package com.nianxi;import org.junit.jupiter.api.Test;public class LeetCode12Test { @Test public void test () { String s = "abciiidef" ; int k = 3 ; System.out.println(maxVowels(s,k)); } public int maxVowels (String s, int k) { char [] ch = s.toCharArray(); int maxCount = 0 ; int temp = 0 ; for (int i = 0 ; i < s.length(); i++) { if (ch[i] == 'a' || ch[i] == 'e' || ch[i] == 'i' || ch[i] == 'o' || ch[i] == 'u' ){ temp++; } if (i <= k - 2 ){ continue ; } if (maxCount < temp){ maxCount = temp; } char out = ch[i-k+1 ]; if (out == 'a' || out == 'e' || out == 'i' || out == 'o' || out == 'u' ){ temp--; } } return maxCount; } }
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 package com.nianxi;import org.junit.jupiter.api.Test;public class LeetCode13Test { @Test public void test () { int [] nums = {-1 }; int k = 1 ; System.out.println(findMaxAverage(nums,k)); } public double findMaxAverage (int [] nums, int k) { int maxSum = Integer.MIN_VALUE; int sum = 0 ; for (int i = 0 ; i < nums.length; i++) { sum += nums[i]; if (i < k - 1 ){ continue ; } maxSum = Math.max(maxSum,sum); sum -= nums[i - k + 1 ]; } return (double ) maxSum / k; } }
3.大小为 K 且平均值大于等于阈值的子数组数目 LeetCode
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 package com.nianxi;import org.junit.jupiter.api.Test;public class LeetCode14Test { @Test public void text () { int [] arr = {2 ,2 ,2 ,2 ,5 ,5 ,5 ,8 }; int k = 3 ; int threshold = 4 ; System.out.println(numOfSubarrays(arr,k,threshold)); } public int numOfSubarrays (int [] arr, int k, int threshold) { int count = 0 ; int sum = 0 ; int average; for (int i = 0 ; i < arr.length; i++) { sum += arr[i]; if (i < k - 1 ){ continue ; } average = sum / k; if (average >= threshold) { count++; } sum -= arr[i-k+1 ]; } return count; } }
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 package com.nianxi;import org.junit.jupiter.api.Test;import java.util.Arrays;public class LeetCode15Test { @Test public void test () { int [] nums = {7 ,4 ,3 ,9 ,1 ,8 ,5 ,2 ,6 }; int k = 3 ; System.out.println(Arrays.toString(getAverages(nums,k))); } public int [] getAverages(int [] nums, int k) { int n = nums.length; int [] ans = new int [n]; Arrays.fill(ans, -1 ); long sum = 0 ; for (int i = 0 ; i < n; i++) { sum += nums[i]; if (i < 2 * k) { continue ; } ans[i - k] = (int ) (sum / (2 * k + 1 )); sum -= nums[i - 2 * k]; } return ans; } }
5.得到 K 个黑块的最少涂色次数 LeetCode
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 package com.nianxi;import org.junit.jupiter.api.Test;public class LeetCode16Test { @Test public void test () { String blocks = "WBBWWBBWBW" ; int k = 7 ; System.out.println(minimumRecolors(blocks, k)); } public int minimumRecolors (String blocks, int k) { char [] s = blocks.toCharArray(); int cntW = 0 ; for (int i = 0 ; i < k; i++) { cntW += s[i] & 1 ; } int ans = cntW; for (int i = k; i < s.length; i++) { cntW += (s[i] & 1 ) - (s[i - k] & 1 ); ans = Math.min(ans, cntW); } return ans; } }