滑动窗口算法(一)
某日事不多,点开sentinel-core代码学习,想看看qps、rt等是怎么统计的。
点开StatisticSlot类,发现里面是用DefaultNode增加qps,然后尝试点开
DefaultNode->StatisticNode->ArrayMetric->MetricsLeapArray->LeapArray...
晕...怎么这么多类- -||| 中间还有MetricBucket、LongAdder...
其中LeapArray类有个属性AtomicReferenceArray<WindowWrap<T>> array,表示这个jdk类也是第一次见orz
看注释写道Using sliding window algorithm,使用了滑动窗口算法。可是这代码太深奥T_T,表示打扰了,还是洗洗睡了Zzz....
--------------------------------------------------------------------------------------------------------------------------------------------
言归正传,虽然sentinel中的代码还看不懂,通过滑动窗口几个字,百度了解一下:)
找到一个经典的问题:
(一)给定一组大小为n的整数数组,计算长度为k的子数组和的最大值。
比如
数组为:1,2,3,4
最大值为:3+4=7
数组为:-1,4,7,-3,8,5,-2,6
最大值为:7-3+8=12
想到最简单思路,那就遍历所有子数组呗,求和然后比较。
int index = 0;// 记录最大子数组第1个元素的索引,目前是0
int maxSum = 0;// 记录最大子数组和,目前是从左开始第1个子数组
for (int i = 0; i < k; i++) {
maxSum += array[i];
}
for (int i = 1; i <= array.length - k; i++) {// 遍历所有子数组,求和并比较
int curSum = 0;
for (int j=0; j < k; j++) {// 计算当前子数组和
curSum += array[i + j];
}
if (curSum > maxSum) {// 如果大于最大和,则记录
maxSum = curSum;
index = i;
}
}
运用滑动窗口思路,遍历时不嵌套循环计算所有值;外层遍历相当于窗口向右滑动,每次减去失效值加上最新值,即为当前窗口的和,然后再比较。
int index = 0;// 记录最大子数组第1个元素的索引,目前是0
int maxSum = 0;// 记录最大子数组和,目前是从左开始第1个子数组
for (int i = 0; i < k; i++) {
maxSum += array[i];
}
int curWindowSum = maxSum;
for (int i = 1; i <= array.length - k; i++) {// 从下个元素开始,即窗口向右滑动
curWindowSum = curWindowSum - array[i - 1] + array[k + i - 1];// 减去失效值,加上最新值
if (curWindowSum > maxSum) {// 如果大于最大和,则记录
maxSum = curWindowSum;
index = i;
}
}
可以看到代码差不多,只不过在计算求和时,采取了滑动窗口技术(思路),通过一减一加求和,消除了内部的循环。
注:这里为了突出语义,将变量名curSum改为curWindowSum
完整代码如下:
package com.cdfive.learn2018.algorithm;
/**
* 求数组array长度为k的子数组的最大和
*
* 算法1-cal
* 遍历所有子数组,求和并比较
* 嵌套循环 O(n*k)
*
* 算法2-calByLeapWinow
* 窗口向右滑动,减去失效值加上最新值
* 单层循环 O(n)
*
* input: array=[1,2,3,4] k=2
* output: 7 // 3+4
*
* input: array=[-1,4,7,-3,8,5,-2,6] k=3
* output: 12 // 7-3+8
*
* @author cdfive
* @date 2018-12-02
*/
public class SimpleLeapWindow1 {
public static void main(String[] args) {
cal(new int[]{1, 2, 3, 4}, 2);
cal(new int[]{-1,4,7,-3,8,5,-2,6}, 3);
System.out.println("-------------");
calByLeapWinow(new int[]{1, 2, 3, 4}, 2);
calByLeapWinow(new int[]{-1,4,7,-3,8,5,-2,6}, 3);
}
/**
* 遍历所有子数组,求和并比较
* 嵌套循环 O(n*k)
*/
public static void cal(int[] array, int k) {
if (array.length == 0 || k <= 0 || k > array.length) {// 非法参数不处理
return;
}
int index = 0;// 记录最大子数组第1个元素的索引,目前是0
int maxSum = 0;// 记录最大子数组和,目前是从左开始第1个子数组
for (int i = 0; i < k; i++) {
maxSum += array[i];
}
for (int i = 1; i <= array.length - k; i++) {// 遍历所有子数组,求和并比较
int curSum = 0;
for (int j=0; j < k; j++) {// 计算当前子数组和
curSum += array[i + j];
}
if (curSum > maxSum) {// 如果大于最大和,则记录
maxSum = curSum;
index = i;
}
}
/**打印结果*/
System.out.print(maxSum + " // ");// 打印最大和
System.out.print(array[index]);// 先打印第1个值
for (int i = 1; i < k; i++) {
int value = array[i + index];
System.out.print(value >= 0 ? ("+" + value) : value);// 非负数前面打印+号
}
System.out.println();
}
/**
* 窗口向右滑动,通过减失效值加最新值求和并比较
* 单层循环 O(n)
*/
public static void calByLeapWinow(int[] array, int k) {
if (array.length == 0 || k <= 0 || k > array.length) {// 非法参数不处理
return;
}
int index = 0;// 记录最大子数组第1个元素的索引,目前是0
int maxSum = 0;// 记录最大子数组和,目前是从左开始第1个子数组
for (int i = 0; i < k; i++) {
maxSum += array[i];
}
int curWindowSum = maxSum;
for (int i = 1; i <= array.length - k; i++) {// 从下个元素开始,即窗口向右滑动
curWindowSum = curWindowSum - array[i - 1] + array[k + i - 1];// 减去失效值,加上最新值
if (curWindowSum > maxSum) {// 如果大于最大和,则记录
maxSum = curWindowSum;
index = i;
}
}
/**打印结果*/
System.out.print(maxSum + " // ");// 打印最大和
System.out.print(array[index]);// 先打印第1个值
for (int i = 1; i < k; i++) {
int value = array[i + index];
System.out.print(value >= 0 ? ("+" + value) : value);// 非负数前面打印+号
}
System.out.println();
}
}
--------------------------------------------------------------------------------------------------------------------------------------------
参考:
滑动窗口法详解 https://blog.csdn.net/sty945/article/details/79846516
Window Sliding Technique https://www.geeksforgeeks.org/window-sliding-technique/
[LeetCode]Sliding Window Algorithm相关题目总结 https://blog.csdn.net/Ellie_/article/details/76781877
分类: algorithm