在解决几何问题时,我遇到了一种称为滑动窗口算法的方法。
真的找不到任何学习材料/细节。
算法是关于什么的?
一般来说,滑动窗口是在底层集合上运行的子列表。即,如果你有一个像
[a b c d e f g h]
一个大小为 3 的滑动窗口会像
[a b c]
[b c d]
[c d e]
[d e f]
[e f g]
[f g h]
例如,如果您想计算运行平均值,或者如果您想创建一组所有相邻对等,这将非常有用。
我认为它更像是一种技术而不是算法。这是一种可用于各种算法的技术。
我认为通过以下示例可以最好地理解该技术。想象一下我们有这个数组:
[ 5, 7, 1, 4, 3, 6, 2, 9, 2 ]
我们如何找到五个连续元素的最大和?好吧,我们首先看看5, 7, 1, 4, 3
总和是20
。然后我们将查看下一组五个连续元素,即7, 1, 4, 3, 6
. 它们的总和是21
。这比我们之前的总和还要多,所以7, 1, 4, 3, 6
目前是我们迄今为止得到的最好的。
让我们看看我们是否可以改进。1, 4, 3, 6, 2
? 不,总和为16
。4, 3, 6, 2, 9
? 总和为24
,所以现在这是我们得到的最佳序列。现在我们进入下一个序列,3, 6, 2, 9, 2
。那个总和为22
,这并没有超过我们目前最好的24
。我们已经到了尽头,所以我们完成了。
以编程方式实现此功能的蛮力方法如下:
const getMaxSumOfFiveContiguousElements = (arr) => {
let maxSum = -Infinity;
let currSum;
for (let i = 0; i <= arr.length - 5; i++) {
currSum = 0;
for (let j = i; j < i + 5; j++) {
currSum += arr[j];
}
maxSum = Math.max(maxSum, currSum);
}
return maxSum;
};
这个时间复杂度是多少?是O(n*k)
。外层循环遍历n - k + 1
项目,但是当n
比 大得多时k
,我们可以忘记这k + 1
部分,只称它为n
项目。然后内部循环正在遍历k
项目,所以我们有O(n*k)
. 尝试像这样可视化它:
我们可以把它归结为justO(n)
吗?让我们回到这个数组:
[ 5, 7, 1, 4, 3, 6, 2, 9, 2 ]
首先我们得到 的总和5, 7, 1, 4, 3
。接下来我们需要 的总和7, 1, 4, 3, 6
。像这样可视化它,每组五个元素都有一个“窗口”。
第一个窗口和第二个窗口有什么区别?好吧,第二个窗口去掉5
了左边的,但6
在右边添加了一个。因此,既然我们知道第一个窗口的总和是20
,为了得到第二个窗口的总和,我们取它20
,减去5
,然后加上6
以获得21
。我们实际上不必遍历第二个窗口中的每个元素并将它们相加(7 + 1 + 4 + 3 + 6
)。这将涉及重复和不必要的工作。
这里的滑动窗口方法最终是两个操作而不是五个,因为k
is 5
。这不是一个巨大的改进,但你可以想象对于更大k
(和更大n
)它确实有帮助。
以下是使用滑动窗口技术的代码如何工作:
const getLargestSumOfFiveConsecutiveElements = (arr) => {
let currSum = getSum(arr, 0, 4);
let largestSum = currSum;
for (let i = 1; i <= arr.length - 5; i++) {
currSum -= arr[i - 1]; // subtract element to the left of curr window
currSum += arr[i + 4]; // add last element in curr window
largestSum = Math.max(largestSum, currSum);
}
return largestSum;
};
const getSum = (arr, start, end) => {
let sum = 0;
for (let i = start; i <= end; i++) {
sum += arr[i];
}
return sum;
};
这就是滑动窗口技术的要点。在其他问题中,您可能会做一些比获取窗口内元素的总和更复杂的事情。或者窗口本身的大小可能不同,而不是我们在这里看到的固定大小的五个。但是滑动窗口技术的这个基本应用应该为您提供一个可以构建的基础。
滑动窗口是一种解决涉及数组/列表问题的技术。在 O(n^2) 或 O(n^3) 中使用蛮力方法很容易解决这些问题。 使用“滑动窗口”技术,我们可以将时间复杂度降低到 O(n)。
很棒的文章在这里:https ://medium.com/outco/how-to-solve-sliding-window-problems-28d67601a66
因此,您希望能够做的第一件事是识别使用滑动窗口范例的问题。幸运的是,有一些常见的赠品:
问题将涉及一个有序且可迭代的数据结构,如数组或字符串
您正在该数组/字符串中寻找一些子范围,例如最长、最短或目标值。
有一个明显的幼稚或蛮力解决方案以 O(N²)、O(2^N) 或其他一些较大的时间复杂度运行。
但最大的收获是,您正在寻找的东西通常是某种最优的,例如完全满足给定条件的最长序列或最短序列。
要添加到以前的答案,这里有一些更多的资源很好地说明了这个概念。
这个 youtube 视频是我在这个主题上找到的最好的。
以下是 leetcode 上可以使用此技术解决的问题列表
滑动窗口是顶级公司的编码轮次中最常见的话题之一,因此绝对值得花一些时间来掌握它。