Max of min for every window size
Problem Statement:
You are given an integer array arr[], the task is to find the maximum of minimum values for every window size k where 1≤ k ≤ arr.size().
For each window size k, consider all contiguous subarrays of length k, determine the minimum element in each subarray, and then take the maximum among all these minimums.
Return the results as an array, where the element at index i represents the answer for window size i+1.
-
Example:
Input:arr[] = [10, 20, 30, 50, 10, 70, 30]
Output:[70, 30, 20, 10, 10, 10, 10]
Explanation:
Window size 1: minimums are [10, 20, 30, 50, 10, 70, 30], maximum of minimums is 70.
Window size 2: minimums are [10, 20, 30, 10, 10, 30], maximum of minimums is 30.
Window size 3: minimums are [10, 20, 10, 10, 10], maximum of minimums is 20.
Window size 4–7: minimums are [10, 10, 10, 10], maximum of minimums is 10.Input:arr[] = [10, 20, 30]
Output:[30, 20, 10]
Explanation:
Window size 1: minimums of [10], [20], [30], maximum of minimums is 30.
Window size 2: minimums of [10, 20], [20,30], maximum of minimums is 20.
Window size 3: minimums of [10,20,30], maximum of minimums is 10.
✅ Solution: Previous/Next Smaller Elements (Stack) — Window-of-Minimums
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
vector<int> maxOfMins(vector<int>& arr) {
int n = arr.size();
vector<int> prevSmaller(n), nextSmaller(n);
stack<int> st;
// Prev smaller element indices (strictly smaller)
while(!st.empty()) st.pop();
for(int i = 0; i < n; ++i){
while(!st.empty() && arr[st.top()] >= arr[i]) st.pop();
prevSmaller[i] = st.empty() ? -1 : st.top();
st.push(i);
}
// Next smaller element indices (strictly smaller)
while(!st.empty()) st.pop();
for(int i = n - 1; i >= 0; --i){
while(!st.empty() && arr[st.top()] >= arr[i]) st.pop();
nextSmaller[i] = st.empty() ? n : st.top();
st.push(i);
}
// res[len] will store the maximum of minimums for windows of length = len
vector<int> res(n + 1, INT_MIN);
for(int i = 0; i < n; ++i){
int length = nextSmaller[i] - prevSmaller[i] - 1; // window length where arr[i] is minimum
res[length] = max(res[length], arr[i]);
}
// Fill empty entries: for smaller window sizes there might be no direct value,
// so propagate max to smaller lengths (monotonicity).
for(int len = n - 1; len >= 1; --len){
res[len] = max(res[len], res[len + 1]);
}
// build answer for window sizes 1..n
vector<int> ans(n);
for(int len = 1; len <= n; ++len) ans[len - 1] = res[len] == INT_MIN ? 0 : res[len];
return ans;
}
};
📝 How It Works
- For each element
arr[i]we find how far it can extend as the minimum in contiguous windows:prevSmaller[i]= index of previous element strictly smaller thanarr[i](or1if none).nextSmaller[i]= index of next element strictly smaller thanarr[i](ornif none).
- The largest window length where
arr[i]is the minimum equalslen = nextSmaller[i] - prevSmaller[i] - 1. - For that
len,arr[i]is a candidate minimum; we recordres[len] = max(res[len], arr[i]). - Finally, some lengths might not get a direct value; we propagate maxima from larger window sizes downwards:
res[k] = max(res[k], res[k+1])fork = n-1 .. 1.
- Return
res[1..n]as the answer (shifted to 0-based vector).
🧩 Key Formula / Relation
-
Window length where
arr[i]is minimum:len(i) = nextSmaller[i] - prevSmaller[i] - 1 -
Final value for a window length
L:ans[L] = max{ arr[i] | len(i) == L } (then propagate ans[L] = max(ans[L], ans[L+1]))
⏱️ Time & Space Complexity
- Time: O(n) — Each element is pushed/popped from the stack at most once; rest are linear passes.
- Space: O(n) — For
prevSmaller,nextSmaller,resand the stack.
⚠️ Edge Cases
- Single element array (
n = 1) — returns that element as the only value. - All elements equal — every window size has the same minimum; propagation handles this correctly.
- Strictly increasing or strictly decreasing arrays — next/prev smaller logic still valid.
- When using
INT_MINas sentinel, ensure final output maps unset entries to an appropriate value (I used0for safety; depending on problem statement you may want another default — often all windows will be filled after propagation so sentinel rarely persists).
💡 Other Approaches
- Brute force sliding windows — O(n²) or O(n³) depending on implementation; impractical for large
n. - Segment tree / RMQ + binary searches — could compute minima over ranges, but still slower and more complex than the linear stack method.
- Divide & conquer — theoretical possibility but more complex and not faster than the stack approach for this problem.
🔁 Related Problems
- "Sliding Window Minimum" — computing min for each fixed-size window (deque method).
- "Maximum of minimum for every window size" (this exact problem / GFG classic).
- "Next Greater Element / Next Smaller Element" family of problems (stack-based).
💬