在解决几何问题时,我遇到了一种称为“滑动窗口算法”的方法。
真的找不到任何学习资料/细节。
算法是关于什么的?
在解决几何问题时,我遇到了一种称为“滑动窗口算法”的方法。
真的找不到任何学习资料/细节。
算法是关于什么的?
Answers:
滑动窗口是解决涉及阵列/列表的问题的技术。使用O(n ^ 2)或O(n ^ 3)中的蛮力方法可以轻松解决这些问题。 使用“滑动窗口”技术,我们可以将时间复杂度降低为O(n)。
伟大的文章在这里:https://medium.com/outco/how-to-solve-sliding-window-problems-28d67601a66
因此,您要做的第一件事就是识别使用滑动窗口范式的问题。幸运的是,有一些常见的赠品:
问题将涉及一个有序且可迭代的数据结构,如数组或字符串
您正在该数组/字符串中寻找某个子范围,例如最长,最短或目标值。
在O(N²),O(2 ^ N)或其他较大的时间复杂度下,有一个简单的幼稚或蛮力解决方案。
但是最大的礼物是,您正在寻找的东西通常是某种最优的,例如恰好满足给定条件的事物的最长序列或最短序列。
我认为它更多的是技术而不是算法。这是一种可以在各种算法中使用的技术。
我认为通过以下示例可以最好地理解该技术。假设我们有这个数组:
[ 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)
。尝试像这样可视化它:
我们可以将其简化为O(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
是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;
};
这就是滑动窗口技术的要点。在其他问题中,您可能要做的事情比获取窗口内元素的总和还要复杂。否则,窗口本身的大小可能会有所变化,而不是我们在此处看到的固定大小(五个)。但是,滑动窗口技术的这一基本应用应该为您提供一个基础,您可以以此为基础。