今有问题如下,给定一个整数数组,计算长度为‘k’的连续子数组的最大总和。
输入:arr[] = {100, 200, 300, 400};
k = 2;
输出:700
解释:300 + 400 = 700
这是一道简单的题目,用暴力法也可以直接解答出来,但今天我们要讨论的是滑窗算法,所以不对暴力解法作太多解答。但为了方便对比,仍然给出暴力解法的答案。
暴力法
unsigned int len = 4;
unsigned int sum = 0;
for (int i = 0; i < len - 1; i++) {
for (int j = i+1; j < i+k; j++) {
sum = sum > (arr[i] + arr[j]) ? sum : (arr[i] + arr[j]);
}
}
暴力解法包含两个for循环,时间复杂度为O(k*n)。
滑动窗口法
滑动窗口算法可以将嵌套的循环问题,转换为单循环问题,降低时间复杂度。
根据示例,当 k 等于 2 时,我们维护一个长度为 2 的窗口。
a、窗口内的值的和保存在一个变量中;
b、通过不断的往右滑动来算出当前窗口的值,并与保存的最大值作比较;
c、当窗口滑动到最右边时终止滑动;
unsigned int len = 4;
for (int i = 0; i < k; i++) { //首先计算出第一个窗口的值. //窗口大小为2
sum += arr[i];
}
unsigned int max = sum;
for (int i = k; i < len; i++) {
sum += arr[i] - arr[i-k]; //新窗口的值= 前一个窗口的值 + 新进入窗口的值 - 移出窗口的值
max = sum > max ? sum:max;
}
return max;
我们在一个循环中计算出了长度为 'k' 的子数组的最大总和,它的时间复杂度是 O(n)。我们可以使用滑动窗口算法解决 查找最大/最小k子阵列,XOR,乘积,求和等问题。