📜  窗口滑动技术

📅  最后修改于: 2022-05-13 01:57:05.900000             🧑  作者: Mango

窗口滑动技术

该技术展示了如何将某些问题中的嵌套 for 循环转换为单个 for 循环以降低时间复杂度。
让我们从一个问题开始,以说明我们可以在哪里应用这种技术——

Given an array of integers of size ‘n’.
Our aim is to calculate the maximum sum of ‘k’ 
consecutive elements in the array.

Input  : arr[] = {100, 200, 300, 400}
         k = 2
Output : 700

Input  : arr[] = {1, 4, 2, 10, 23, 3, 1, 0, 20}
         k = 4 
Output : 39
We get maximum sum by adding subarray {4, 2, 10, 23}
of size 4.

Input  : arr[] = {2, 3}
         k = 3
Output : Invalid
There is no subarray of size 3 as size of whole
array is 2.

那么,让我们来分析一下蛮力方法的问题。我们从第一个索引开始并求和直到第 k 个元素。我们对所有可能的连续块或 k 个元素组进行此操作。此方法需要嵌套 for 循环,外部 for 循环从 k 个元素块的起始元素开始,内部或嵌套循环将累加到第 k 个元素。

考虑以下实现:

C++
// O(n*k) solution for finding maximum sum of
// a subarray of size k
#include 
using namespace std;
 
// Returns maximum sum in a subarray of size k.
int maxSum(int arr[], int n, int k)
{
    // Initialize result
    int max_sum = INT_MIN;
 
    // Consider all blocks starting with i.
    for (int i = 0; i < n - k + 1; i++) {
        int current_sum = 0;
        for (int j = 0; j < k; j++)
            current_sum = current_sum + arr[i + j];
 
        // Update result if required.
        max_sum = max(current_sum, max_sum);
    }
 
    return max_sum;
}
 
// Driver code
int main()
{
    int arr[] = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };
    int k = 4;
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << maxSum(arr, n, k);
    return 0;
}


Java
// Java code here
// O(n*k) solution for finding
// maximum sum of a subarray
// of size k
class GFG {
    // Returns maximum sum in
    // a subarray of size k.
    static int maxSum(int arr[], int n, int k)
    {
        // Initialize result
        int max_sum = Integer.MIN_VALUE;
 
        // Consider all blocks starting with i.
        for (int i = 0; i < n - k + 1; i++) {
            int current_sum = 0;
            for (int j = 0; j < k; j++)
                current_sum = current_sum + arr[i + j];
 
            // Update result if required.
            max_sum = Math.max(current_sum, max_sum);
        }
 
        return max_sum;
    }
 
    // Driver code
    public static void main(String[] args)
    {
        int arr[] = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };
        int k = 4;
        int n = arr.length;
        System.out.println(maxSum(arr, n, k));
    }
}
 
// This code is contributed
// by  prerna saini.


Python3
# code
import sys
print ("GFG")
# O(n * k) solution for finding
# maximum sum of a subarray of size k
INT_MIN = -sys.maxsize - 1
 
# Returns maximum sum in a
# subarray of size k.
 
 
def maxSum(arr, n, k):
 
    # Initialize result
    max_sum = INT_MIN
 
    # Consider all blocks
    # starting with i.
    for i in range(n - k + 1):
        current_sum = 0
        for j in range(k):
            current_sum = current_sum + arr[i + j]
 
        # Update result if required.
        max_sum = max(current_sum, max_sum)
 
    return max_sum
 
 
# Driver code
arr = [1, 4, 2, 10, 2,
       3, 1, 0, 20]
k = 4
n = len(arr)
print(maxSum(arr, n, k))
 
# This code is contributed by mits


C#
// C# code here O(n*k) solution for
// finding maximum sum of a subarray
// of size k
using System;
 
class GFG {
 
    // Returns maximum sum in a
    // subarray of size k.
    static int maxSum(int[] arr, int n, int k)
    {
        // Initialize result
        int max_sum = int.MinValue;
 
        // Consider all blocks starting
        // with i.
        for (int i = 0; i < n - k + 1; i++) {
            int current_sum = 0;
            for (int j = 0; j < k; j++)
                current_sum = current_sum + arr[i + j];
 
            // Update result if required.
            max_sum = Math.Max(current_sum, max_sum);
        }
 
        return max_sum;
    }
 
    // Driver code
    public static void Main()
    {
        int[] arr = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };
        int k = 4;
        int n = arr.Length;
        Console.WriteLine(maxSum(arr, n, k));
    }
}
 
// This code is contributed by anuj_67.


PHP



Javascript


C++
// O(n) solution for finding maximum sum of
// a subarray of size k
#include 
using namespace std;
 
// Returns maximum sum in a subarray of size k.
int maxSum(int arr[], int n, int k)
{
    // n must be greater
    if (n < k) {
        cout << "Invalid";
        return -1;
    }
 
    // Compute sum of first window of size k
    int max_sum = 0;
    for (int i = 0; i < k; i++)
        max_sum += arr[i];
 
    // Compute sums of remaining windows by
    // removing first element of previous
    // window and adding last element of
    // current window.
    int window_sum = max_sum;
    for (int i = k; i < n; i++) {
        window_sum += arr[i] - arr[i - k];
        max_sum = max(max_sum, window_sum);
    }
 
    return max_sum;
}
 
// Driver code
int main()
{
    int arr[] = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };
    int k = 4;
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << maxSum(arr, n, k);
    return 0;
}


Java
// Java code for
// O(n) solution for finding
// maximum sum of a subarray
// of size k
class GFG {
 
    // Returns maximum sum in
    // a subarray of size k.
    static int maxSum(int arr[], int n, int k)
    {
        // n must be greater
        if (n < k) {
            System.out.println("Invalid");
            return -1;
        }
 
        // Compute sum of first window of size k
        int max_sum = 0;
        for (int i = 0; i < k; i++)
            max_sum += arr[i];
 
        // Compute sums of remaining windows by
        // removing first element of previous
        // window and adding last element of
        // current window.
        int window_sum = max_sum;
        for (int i = k; i < n; i++) {
            window_sum += arr[i] - arr[i - k];
            max_sum = Math.max(max_sum, window_sum);
        }
 
        return max_sum;
    }
 
    // Driver code
    public static void main(String[] args)
    {
        int arr[] = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };
        int k = 4;
        int n = arr.length;
        System.out.println(maxSum(arr, n, k));
    }
}
 
// This code is contributed
// by  prerna saini.


Python3
# O(n) solution for finding
# maximum sum of a subarray of size k
 
 
def maxSum(arr, k):
    # length of the array
    n = len(arr)
 
    # n must be greater than k
    if n < k:
        print("Invalid")
        return -1
 
    # Compute sum of first window of size k
    window_sum = sum(arr[:k])
 
    # first sum available
    max_sum = window_sum
 
    # Compute the sums of remaining windows by
    # removing first element of previous
    # window and adding last element of
    # the current window.
    for i in range(n - k):
        window_sum = window_sum - arr[i] + arr[i + k]
        max_sum = max(window_sum, max_sum)
 
    return max_sum
 
 
# Driver code
arr = [1, 4, 2, 10, 2, 3, 1, 0, 20]
k = 4
print(maxSum(arr, k))
 
# This code is contributed by Kyle McClay


C#
// C# code for O(n) solution for finding
// maximum sum of a subarray of size k
using System;
 
class GFG {
 
    // Returns maximum sum in
    // a subarray of size k.
    static int maxSum(int[] arr, int n, int k)
    {
 
        // n must be greater
        if (n < k) {
            Console.WriteLine("Invalid");
            return -1;
        }
 
        // Compute sum of first window of size k
        int max_sum = 0;
        for (int i = 0; i < k; i++)
            max_sum += arr[i];
 
        // Compute sums of remaining windows by
        // removing first element of previous
        // window and adding last element of
        // current window.
        int window_sum = max_sum;
        for (int i = k; i < n; i++) {
            window_sum += arr[i] - arr[i - k];
            max_sum = Math.Max(max_sum, window_sum);
        }
 
        return max_sum;
    }
 
    // Driver code
    public static void Main()
    {
        int[] arr = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };
        int k = 4;
        int n = arr.Length;
        Console.WriteLine(maxSum(arr, n, k));
    }
}
 
// This code is contributed by anuj_67.


PHP


Javascript
// Javascript code for
// O(n) solution for finding
// maximum sum of a subarray
// of size k
function maxSumofK(arr, k) {
let max = 0;
let sum = 0;
//find initial sum of first k elements
for(let n = 0; n <  k ; n++) {
    sum +=  arr[n];      
}
//iterate the array once and increment the right edge
 for(let i = k; i < arr.length; i++) {    
        sum += arr[i] - arr[i-k];
        //compare if sum is more than max, if yes then replace max with new sum value
           if(sum > max) {
               max = sum;
           }
        }
    return max;
}
 
let arr = [1, 4, 2, 10, 2, 3, 1, 0, 20 ];
console.log(maxSumofK(arr, 4))
//output 28


输出
24

从上面的代码可以看出,时间复杂度为O(k*n) ,因为它包含两个嵌套循环。

窗口滑动技术

使用总线中的窗格可以最好地理解该技术,考虑一个长度为n的窗口和固定在其中的长度为k的窗格。考虑一下,最初窗格位于最左侧,即距左侧 0 个单位。现在,将窗口与大小为 n 的数组 arr[] 关联起来,将窗格与大小为 k 个元素的 current_sum 关联起来。现在,如果我们对窗户施加力,使其向前移动一个单位距离。该窗格将覆盖接下来的k个连续元素。
考虑一个数组arr[] = {5, 2, -1, 0, 3} 和k = 3 和n = 5 的值
应用滑动窗口技术

  1. 我们使用线性循环计算 n 项中前 k 个元素的总和,并将总和存储在变量 window_sum 中。
  2. 然后我们将线性掠过数组直到它到达末尾,同时跟踪最大和。
  3. 要获得 k 个元素块的当前总和,只需从前一个块中减去第一个元素并添加当前块的最后一个元素。

下面的表示将清楚地说明窗口如何在数组上滑动。
这是我们从索引 0 开始计算初始窗口总和的初始阶段。在这个阶段,窗口总和为 6。现在,我们将 maximum_sum 设置为 current_window,即 6。

现在,我们将窗口滑动一个单位索引。因此,现在它从窗口中丢弃 5 并将 0 添加到窗口中。因此,我们将通过减去 5 然后加 0 来获得我们的新窗口总和。所以,我们的窗口总和现在变为 1。现在,我们将把这个窗口总和与 maximum_sum 进行比较。由于它更小,我们不会更改最大和。

类似地,现在我们再次将窗口滑动一个单位索引并获得新的窗口总和为 2。我们再次检查当前窗口总和是否大于现在的 maximum_sum。再一次,它变小了,所以我们不改变maximum_sum。
因此,对于上述数组,我们的 maximum_sum 为 6。

上述描述的代码:

C++

// O(n) solution for finding maximum sum of
// a subarray of size k
#include 
using namespace std;
 
// Returns maximum sum in a subarray of size k.
int maxSum(int arr[], int n, int k)
{
    // n must be greater
    if (n < k) {
        cout << "Invalid";
        return -1;
    }
 
    // Compute sum of first window of size k
    int max_sum = 0;
    for (int i = 0; i < k; i++)
        max_sum += arr[i];
 
    // Compute sums of remaining windows by
    // removing first element of previous
    // window and adding last element of
    // current window.
    int window_sum = max_sum;
    for (int i = k; i < n; i++) {
        window_sum += arr[i] - arr[i - k];
        max_sum = max(max_sum, window_sum);
    }
 
    return max_sum;
}
 
// Driver code
int main()
{
    int arr[] = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };
    int k = 4;
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << maxSum(arr, n, k);
    return 0;
}

Java

// Java code for
// O(n) solution for finding
// maximum sum of a subarray
// of size k
class GFG {
 
    // Returns maximum sum in
    // a subarray of size k.
    static int maxSum(int arr[], int n, int k)
    {
        // n must be greater
        if (n < k) {
            System.out.println("Invalid");
            return -1;
        }
 
        // Compute sum of first window of size k
        int max_sum = 0;
        for (int i = 0; i < k; i++)
            max_sum += arr[i];
 
        // Compute sums of remaining windows by
        // removing first element of previous
        // window and adding last element of
        // current window.
        int window_sum = max_sum;
        for (int i = k; i < n; i++) {
            window_sum += arr[i] - arr[i - k];
            max_sum = Math.max(max_sum, window_sum);
        }
 
        return max_sum;
    }
 
    // Driver code
    public static void main(String[] args)
    {
        int arr[] = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };
        int k = 4;
        int n = arr.length;
        System.out.println(maxSum(arr, n, k));
    }
}
 
// This code is contributed
// by  prerna saini.

Python3

# O(n) solution for finding
# maximum sum of a subarray of size k
 
 
def maxSum(arr, k):
    # length of the array
    n = len(arr)
 
    # n must be greater than k
    if n < k:
        print("Invalid")
        return -1
 
    # Compute sum of first window of size k
    window_sum = sum(arr[:k])
 
    # first sum available
    max_sum = window_sum
 
    # Compute the sums of remaining windows by
    # removing first element of previous
    # window and adding last element of
    # the current window.
    for i in range(n - k):
        window_sum = window_sum - arr[i] + arr[i + k]
        max_sum = max(window_sum, max_sum)
 
    return max_sum
 
 
# Driver code
arr = [1, 4, 2, 10, 2, 3, 1, 0, 20]
k = 4
print(maxSum(arr, k))
 
# This code is contributed by Kyle McClay

C#

// C# code for O(n) solution for finding
// maximum sum of a subarray of size k
using System;
 
class GFG {
 
    // Returns maximum sum in
    // a subarray of size k.
    static int maxSum(int[] arr, int n, int k)
    {
 
        // n must be greater
        if (n < k) {
            Console.WriteLine("Invalid");
            return -1;
        }
 
        // Compute sum of first window of size k
        int max_sum = 0;
        for (int i = 0; i < k; i++)
            max_sum += arr[i];
 
        // Compute sums of remaining windows by
        // removing first element of previous
        // window and adding last element of
        // current window.
        int window_sum = max_sum;
        for (int i = k; i < n; i++) {
            window_sum += arr[i] - arr[i - k];
            max_sum = Math.Max(max_sum, window_sum);
        }
 
        return max_sum;
    }
 
    // Driver code
    public static void Main()
    {
        int[] arr = { 1, 4, 2, 10, 2, 3, 1, 0, 20 };
        int k = 4;
        int n = arr.Length;
        Console.WriteLine(maxSum(arr, n, k));
    }
}
 
// This code is contributed by anuj_67.

PHP


Javascript

// Javascript code for
// O(n) solution for finding
// maximum sum of a subarray
// of size k
function maxSumofK(arr, k) {
let max = 0;
let sum = 0;
//find initial sum of first k elements
for(let n = 0; n <  k ; n++) {
    sum +=  arr[n];      
}
//iterate the array once and increment the right edge
 for(let i = k; i < arr.length; i++) {    
        sum += arr[i] - arr[i-k];
        //compare if sum is more than max, if yes then replace max with new sum value
           if(sum > max) {
               max = sum;
           }
        }
    return max;
}
 
let arr = [1, 4, 2, 10, 2, 3, 1, 0, 20 ];
console.log(maxSumofK(arr, 4))
//output 28
输出
24

现在,很明显时间复杂度是线性的,因为我们可以看到在我们的代码中只运行了一个循环。因此,我们的时间复杂度是O(n)
我们可以使用这种技术来查找最大/最小 k 子数组、XOR、乘积、总和等。有关此类问题,请参阅滑动窗口问题。
https://youtu.be/9-3BXsfrpbY?list=PLqM7alHXFySEQDk2MDfbwEdjd2svVJH9p