You have heard about doing it in O(n) using dequeue.
Well that is a well known algorithm for this question to do in O(n).
The method i am telling is quite simple and has time complexity O(n).
Your Sample Input:
n=10 , W = 3
10 3
1 -2 5 6 0 9 8 -1 2 0
Answer = 5 6 6 9 9 9 8 2
Concept: Dynamic Programming
Algorithm:
- N is number of elements in an array and W is window size. So, Window number = N-W+1
-
Now divide array into blocks of W starting from index 1.
Here divide into blocks of size ‘W’=3.
For your sample input: -
We have divided into blocks because we will calculate maximum in 2 ways A.) by traversing from left to right B.) by traversing from right to left.
but how ?? -
Firstly, Traversing from Left to Right. For each element
ai
in block we will find maximum till that elementai
starting from START of Block to END of that block.
So here, -
Secondly, Traversing from Right to Left. For each element
'ai'
in block we will find maximum till that element'ai'
starting from END of Block to START of that block.
So Here, -
Now we have to find maximum for each subarray or window of size ‘W’.
So, starting from index = 1 to index = N-W+1 .max_val[index] = max(RL[index], LR[index+w-1]);
for index=1: max_val[1] = max(RL[1],LR[3]) = max(5,5)= 5
Simliarly, for all index
i
,(i<=(n-k+1))
, value atRL[i]
andLR[i+w-1]
are compared and maximum among those two is answer for that subarray.
So Final Answer : 5 6 6 9 9 9 8 2
Time Complexity: O(n)
Implementation code:
// Shashank Jain
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LIM 100001
using namespace std;
int arr[LIM]; // Input Array
int LR[LIM]; // maximum from Left to Right
int RL[LIM]; // maximum from Right to left
int max_val[LIM]; // number of subarrays(windows) will be n-k+1
int main(){
int n, w, i, k; // 'n' is number of elements in array
// 'w' is Window's Size
cin >> n >> w;
k = n - w + 1; // 'K' is number of Windows
for(i = 1; i <= n; i++)
cin >> arr[i];
for(i = 1; i <= n; i++){ // for maximum Left to Right
if(i % w == 1) // that means START of a block
LR[i] = arr[i];
else
LR[i] = max(LR[i - 1], arr[i]);
}
for(i = n; i >= 1; i--){ // for maximum Right to Left
if(i == n) // Maybe the last block is not of size 'W'.
RL[i] = arr[i];
else if(i % w == 0) // that means END of a block
RL[i] = arr[i];
else
RL[i] = max(RL[i+1], arr[i]);
}
for(i = 1; i <= k; i++) // maximum
max_val[i] = max(RL[i], LR[i + w - 1]);
for(i = 1; i <= k ; i++)
cout << max_val[i] << " ";
cout << endl;
return 0;
}
I’ll try to proof: (by @johnchen902)
If k % w != 1
(k
is not the begin of a block)
Let k* = The begin of block containing k
ans[k] = max( arr[k], arr[k + 1], arr[k + 2], ..., arr[k + w - 1])
= max( max( arr[k], arr[k + 1], arr[k + 2], ..., arr[k*]),
max( arr[k*], arr[k* + 1], arr[k* + 2], ..., arr[k + w - 1]) )
= max( RL[k], LR[k+w-1] )
Otherwise (k
is the begin of a block)
ans[k] = max( arr[k], arr[k + 1], arr[k + 2], ..., arr[k + w - 1])
= RL[k] = LR[k+w-1]
= max( RL[k], LR[k+w-1] )