在 O(n) 时间内使用堆栈滑动窗口最大值(所有大小为 k 的子数组的最大值)
给出一个包含N个整数和另一个整数k ≤ N的数组arr[] 。任务是找到每个大小为k的子数组的最大元素。
例子:
Input: arr[] = {9, 7, 2, 4, 6, 8, 2, 1, 5}
k = 3
Output: 9 7 6 8 8 8 5
Explanation:
Window 1: {9, 7, 2}, max = 9
Window 2: {7, 2, 4}, max = 7
Window 3: {2, 4, 6}, max = 6
Window 4: {4, 6, 8}, max = 8
Window 5: {6, 8, 2}, max = 8
Window 6: {8, 2, 1}, max = 8
Window 7: {2, 1, 5}, max = 5
Input: arr[] = {6, 7, 5, 2, 1, 7, 2, 1, 10}
k = 2
Output: 7 7 5 2 7 7 2 10
Explanation:
Window 1: {6, 7}, max = 7
Window 2: {7, 5}, max = 7
Window 3: {5, 2}, max = 5
Window 4: {2, 1}, max = 2
Window 5: {1, 7}, max = 7
Window 6: {7, 2}, max = 7
Window 7: {2, 1}, max = 2
Window 8: {1, 10}, max = 10
先决条件:下一个更大的元素
方法:
对于每个索引,计算子数组从该索引开始时当前元素最大的索引,即对于每个索引i ,索引j ≥ i使得max(a[i], a[i + 1], ... a[ j]) = a[i] 。让我们称之为max_upto[i] 。
然后从第 i个索引开始的长度为k的子数组中的最大元素,可以通过检查从i到i + k – 1的每个索引找到max_upto[i] ≥ i + k – 1 (最后一个索引那个窗口)。
堆栈数据结构可用于将值存储在窗口中,即最后访问或先前插入的元素将位于顶部(与当前元素具有最接近索引的元素)。
算法:
- 创建一个数组max_upto和一个堆栈来存储索引。将 0 压入堆栈。
- 运行从索引 1 到索引 n-1 的循环。
- 从堆栈中弹出所有索引,其中元素(array[s.top()])小于当前元素并更新max_upto[s.top()] = i – 1然后将 i 插入堆栈。
- 从堆栈中弹出所有索引并分配max_upto[s.top()] = n – 1 。
- 创建一个变量j = 0
- 运行一个从 0 到 n - k 的循环,循环计数器为 i
- 运行一个嵌套循环,直到 j < i 或 max_upto[j] < i + k – 1,在每次迭代中递增 j。
- 打印第 j 个数组元素。
执行:
C++
// C++ implementation of the approach
#include
using namespace std;
// Function to print the maximum for
// every k size sub-array
void print_max(int a[], int n, int k)
{
// max_upto array stores the index
// upto which the maximum element is a[i]
// i.e. max(a[i], a[i + 1], ... a[max_upto[i]]) = a[i]
int max_upto[n];
// Update max_upto array similar to
// finding next greater element
stack s;
s.push(0);
for (int i = 1; i < n; i++) {
while (!s.empty() && a[s.top()] < a[i]) {
max_upto[s.top()] = i - 1;
s.pop();
}
s.push(i);
}
while (!s.empty()) {
max_upto[s.top()] = n - 1;
s.pop();
}
int j = 0;
for (int i = 0; i <= n - k; i++) {
// j < i is to check whether the
// jth element is outside the window
while (j < i || max_upto[j] < i + k - 1)
j++;
cout << a[j] << " ";
}
cout << endl;
}
// Driver code
int main()
{
int a[] = { 9, 7, 2, 4, 6, 8, 2, 1, 5 };
int n = sizeof(a) / sizeof(int);
int k = 3;
print_max(a, n, k);
return 0;
}
Java
// Java implementation of the approach
import java.util.*;
class GFG
{
// Function to print the maximum for
// every k size sub-array
static void print_max(int a[], int n, int k)
{
// max_upto array stores the index
// upto which the maximum element is a[i]
// i.e. max(a[i], a[i + 1], ... a[max_upto[i]]) = a[i]
int[] max_upto = new int[n];
// Update max_upto array similar to
// finding next greater element
Stack s = new Stack<>();
s.push(0);
for (int i = 1; i < n; i++)
{
while (!s.empty() && a[s.peek()] < a[i])
{
max_upto[s.peek()] = i - 1;
s.pop();
}
s.push(i);
}
while (!s.empty())
{
max_upto[s.peek()] = n - 1;
s.pop();
}
int j = 0;
for (int i = 0; i <= n - k; i++)
{
// j < i is to check whether the
// jth element is outside the window
while (j < i || max_upto[j] < i + k - 1)
{
j++;
}
System.out.print(a[j] + " ");
}
System.out.println();
}
// Driver code
public static void main(String[] args)
{
int a[] = {9, 7, 2, 4, 6, 8, 2, 1, 5};
int n = a.length;
int k = 3;
print_max(a, n, k);
}
}
// This code has been contributed by 29AjayKumar
Python3
# Python3 implementation of the approach
# Function to print the maximum for
# every k size sub-array
def print_max(a, n, k):
# max_upto array stores the index
# upto which the maximum element is a[i]
# i.e. max(a[i], a[i + 1], ... a[max_upto[i]]) = a[i]
max_upto=[0 for i in range(n)]
# Update max_upto array similar to
# finding next greater element
s=[]
s.append(0)
for i in range(1,n):
while (len(s) > 0 and a[s[-1]] < a[i]):
max_upto[s[-1]] = i - 1
del s[-1]
s.append(i)
while (len(s) > 0):
max_upto[s[-1]] = n - 1
del s[-1]
j = 0
for i in range(n - k + 1):
# j < i is to check whether the
# jth element is outside the window
while (j < i or max_upto[j] < i + k - 1):
j += 1
print(a[j], end=" ")
print()
# Driver code
a = [9, 7, 2, 4, 6, 8, 2, 1, 5]
n = len(a)
k = 3
print_max(a, n, k)
# This code is contributed by mohit kumar
C#
// C# implementation of the approach
using System;
using System.Collections.Generic;
class GFG
{
// Function to print the maximum for
// every k size sub-array
static void print_max(int []a, int n, int k)
{
// max_upto array stores the index
// upto which the maximum element is a[i]
// i.e. max(a[i], a[i + 1], ... a[max_upto[i]]) = a[i]
int[] max_upto = new int[n];
// Update max_upto array similar to
// finding next greater element
Stack s = new Stack();
s.Push(0);
for (int i = 1; i < n; i++)
{
while (s.Count!=0 && a[s.Peek()] < a[i])
{
max_upto[s.Peek()] = i - 1;
s.Pop();
}
s.Push(i);
}
while (s.Count!=0)
{
max_upto[s.Peek()] = n - 1;
s.Pop();
}
int j = 0;
for (int i = 0; i <= n - k; i++)
{
// j < i is to check whether the
// jth element is outside the window
while (j < i || max_upto[j] < i + k - 1)
{
j++;
}
Console.Write(a[j] + " ");
}
Console.WriteLine();
}
// Driver code
public static void Main(String[] args)
{
int []a = {9, 7, 2, 4, 6, 8, 2, 1, 5};
int n = a.Length;
int k = 3;
print_max(a, n, k);
}
}
// This code has been contributed by 29AjayKumar
Javascript
输出:
9 7 6 8 8 8 5
复杂性分析:
- 时间复杂度: O(n)。
只需要遍历数组两次。所以时间复杂度是O(n)。 - 空间复杂度: O(n)。
需要两个大小为 n 的额外空间。
https://youtu.be/m
-Dqu7csdJk?list=PLqM7alHXFySEQDk2MDfbwEdjd2svVJH9p