,  

Find maximum of minimum for every window size in a given array

Problem: Given an integer array of size n, find the maximum of the minimum’s of every window size in the array.

For example:
Input: arr[] = {10, 20, 30, 50, 10, 70, 30}
Output: 7 3 2 1 1 1 1

First element in output indicates maximum of minimums of all 
windows of size 1.
Minimums of windows of size 1 are {1}, {2}, {3}, {5}, {1},
{7} and {3}. Maximum of these minimums is 7

Second element in output indicates maximum of minimums of all 
windows of size 2.
Minimums of windows of size 2 are {1}, {2}, {3}, {1}, {1},
and {3}.  Maximum of these minimums is 3

Third element in output indicates maximum of minimums of all 
windows of size 3.
Minimums of windows of size 3 are {1}, {2}, {1}, {1} and {1}. 
Maximum of these minimums is 2

Similarly other elements of output are computed.
Method 1: The brute-force is to consider sub-array of all size and then find the maximum of all sub-arrays.
class practice
{   
    /* method to print the required result */  
    static void printMaxOfMin(int arr[], int n)
    {
        /* Consider all windows of different sizes starting
           from size 1 */
        for (int k=1; k<=n; k++)
        {
            /* initialize max of min for current window size k */
            int maxOfMin = arr[0];
      
            /* traverse through all windows of current size k */
            for (int i = 0; i <= n-k; i++)
            {
                /* Finding minimum of current window */
                int min = arr[i];
                for (int j = 1; j < k; j++)
                {
                    if (arr[i+j] < min)
                        min = arr[i+j];
                }
      
                /* Update maxOfMin if required */
                if (min > maxOfMin)
                  maxOfMin = min;
            }
      
            /* Print max of min for current window size */
            System.out.print(maxOfMin + " ");
        }
    }
     
    /* driver method */
    public static void main(String[] args) 
    {
        int arr[]  = {1, 2, 3, 5, 1, 7, 3};
        printMaxOfMin(arr, arr.length);
    }
}
Output:
7 3 2 1 1 1 1
Time Complexity: O(n3) and Space Complexity: O(1)

Method 2: If we work bit hard, we can come out with O(n) algorithm. The idea is to use auxiliary for pre-proccessing.

1. Find indexes of next smaller and previous smaller for every element.

Next smaller: is the nearest smallest element on right side of arr[i]. 
Similarly, Previous smaller: is the nearest smallest element on left side of arr[i]. 
If there is no smaller element on right side, then next smaller is n.If there is no smaller on left side, then previous smaller is -1. 

For input {10, 20, 30, 50, 10, 70, 30}, array of indexes of next smaller is {7, 4, 4, 4, 7, 6, 7} and array of indexes of previous smaller is {-1, 0, 1, 2, -1, 4, 4}. 
This step can be done in O(n). Refer this post.

2. Once we have indexes of next and previous smaller, we know that arr[i] is a minimum of a window of length “right[i] – left[i] – 1”. Lengths of windows for which the elements are minimum are {7, 3, 2, 1, 7, 1, 2}. This array indicates, first element is minimum in window of size 7, second element is minimum in window of size 3, and so on. 

Create an auxiliary array ans[n+1] to store the result. Values in ans[] can be filled by iterating through right[] and left[]
    for (int i=0; i < n; i++)
    {
        // length of the interval
        int len = right[i] - left[i] - 1;

        // a[i] is the possible answer for
        // this length len interval
        ans[len] = max(ans[len], arr[i]);
    }
We get the ans[] array as {0, 70, 30, 20, 0, 0, 0, 10}. Note that ans[0] or answer for length 0 is useless. 

3. Some entries in ans[] are 0 and yet to be filled. For example, we know maximum of minimum for lengths 1, 2, 3 and 7 are 70, 30, 20 and 10 respectively, but we don’t know the same for lengths 4, 5 and 6. 

Below are few important observations to fill remaining entries 
a) Result for length i, i.e. ans[i] would always be greater or same as result for length i+1, i.e., ans[i+1].
b) If ans[i] is not filled it means there is no direct element which is minimum of length i and therefore either the element of length ans[i+1], or ans[i+2], and so on is same as ans[i] 

So we fill rest of the entries using below loop.
    for (int i=n-1; i>=1; i--)
        ans[i] = max(ans[i], ans[i+1]);
Below is implementation of above algorithm.
import java.util.Stack;
 
class practice
{    
    /* method to print the required result */
    static void printMaxOfMin(int arr[], int n)
    {
        /* used to find previous and next smaller */
        Stack s = new Stack<>();
      
        /* Arrays to store previous and next smaller */
        int left[] = new int[n+1];  
        int right[]  = new int[n+1]; 
      
        /* Initialize elements of left[] and right[] */
        for (int i=0; i= arr[i])
                s.pop();
      
            if (!s.empty())
                left[i] = s.peek();
      
            s.push(i);
        }
      
        /* use same stack for right[] */
        while (!s.empty())
            s.pop();
      
        /* filling the right[] array */
        for (int i = n-1 ; i>=0 ; i-- )
        {
            while (!s.empty() && arr[s.peek()] >= arr[i])
                s.pop();
      
            if(!s.empty())
                right[i] = s.peek();
      
            s.push(i);
        }
      
        /* initial answer array */
        int ans[] = new int[n+1];
        for (int i=0; i<=n; i++)
            ans[i] = 0;
      
        /* Fill answer array by comparing minimums of all
           lengths computed using left[] and right[] */
        for (int i=0; i=1; i--)
            ans[i] = Math.max(ans[i], ans[i+1]);
      
        /* printing result */
        for (int i=1; i<=n; i++)
            System.out.print(ans[i] + " ");
    }
     
    /* driver function */
    public static void main(String[] args) 
    {
        int arr[] = {1, 2, 3, 5, 1, 7, 3};
        printMaxOfMin(arr, arr.length);
    }
}
Output:
7 3 2 1 1 1 1
Time Complexity: O(n) and Space Complexity: O(2*n)