Maximum water that can be stored between two buildings

Given an integer array which represents the heights of N buildings, the task is to delete N-2 buildings such that the water that can be trapped between the remaining two building is maximum.

Examples:

Input: arr[] = {1, 3, 4}
Output: 1
We have to calculate the maximum water that can be stored between any 2 buildings.
Water between the buildings of height 1 and height 3 = 0.
Water between the buildings of height 1 and height 4 = 1.
Water between the buildings of height 3 and height 4 = 0.
Hence maximum of all the cases is 1.



Input: arr[] = {2, 1, 3, 4, 6, 5}
Output: 8

Naive approach:
Check for all possible pairs and the pair which can hold maximum water will be the answer.
Water stored between two buildings of height h1 and h2 would be equal to:

minimum(h1, h2)*(distance between the buildings-1)

Our task is to maximize this value for every pair.

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// CPP implementation of the above approach
#include <bits/stdc++.h>
using namespace std;
  
// Return the maximum water that can be stored
int maxWater(int height[], int n)
{
    int maximum = 0;
  
    // Check all possible pairs of buildings
    for (int i = 0; i < n - 1; i++) {
        for (int j = i + 1; j < n; j++) {
            int current = (min(height[i],
                               height[j])
                           * (j - i - 1));
  
            // Maximum so far
            maximum = max(maximum, current);
        }
    }
    return maximum;
}
  
// Driver code
int main()
{
    int height[] = { 2, 1, 3, 4, 6, 5 };
    int n = sizeof(height) / sizeof(height[0]);
    cout << maxWater(height, n);
    return 0;
}
  
// This code is contributed by ihritik

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation of the above approach
class GFG {
  
    // Return the maximum water that can be stored
    static int maxWater(int height[], int n)
    {
        int max = 0;
  
        // Check all possible pairs of buildings
        for (int i = 0; i < n - 1; i++) {
            for (int j = i + 1; j < n; j++) {
                int current = (Math.min(height[i],
                                        height[j])
                               * (j - i - 1));
  
                // Maximum so far
                max = Math.max(max, current);
            }
        }
        return max;
    }
  
    // Driver code
    public static void main(String[] args)
    {
        int height[] = { 2, 1, 3, 4, 6, 5 };
        int n = height.length;
        System.out.print(maxWater(height, n));
    }
}

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 code for the above approach 
  
# Return the maximum water 
# that can be stored 
def maxWater(height, n) :
    maximum = 0
  
    # Check all possible pairs of buildings 
    for i in range(n - 1) :
        for j in range(i + 1, n) :
            current = min(height[i], 
                          height[j]) * (j - i - 1); 
  
            # Maximum so far 
            maximum = max(maximum, current); 
              
    return maximum; 
      
# Driver code 
if __name__ == "__main__" :
    height = [ 2, 1, 3, 4, 6, 5 ];
      
    n = len(height); 
    print(maxWater(height, n)); 
  
# This code is contributed by AnkitRai01

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# implementation of the above approach
using System;
  
class GFG {
  
    // Return the maximum water that can be stored
    static int maxWater(int[] height, int n)
    {
        int max = 0;
  
        // Check all possible pairs of buildings
        for (int i = 0; i < n - 1; i++) {
            for (int j = i + 1; j < n; j++) {
                int current = (Math.Min(height[i],
                                        height[j])
                               * (j - i - 1));
  
                // Maximum so far
                max = Math.Max(max, current);
            }
        }
        return max;
    }
  
    // Driver code
    static public void Main()
    {
        int[] height = { 2, 1, 3, 4, 6, 5 };
        int n = height.Length;
        Console.WriteLine(maxWater(height, n));
    }
}
  
// This code is ontributed by @tushil.

chevron_right


Output:

8

Time Complexity : O(N*N).

Efficient approach:

  • Sort the array according to increasing height without affecting the original indices i.e. make pairs of (element, index).
  • Then for every element, assume it is the building with the minimum height among the two buildings required then the height of the required water will be equal to the height of the chosen building and the width will be equal to the index difference between the chosen building and the building to be found.
  • In order to choose the other building which maximizes the water, the other building has to be as far as possible and must be greater in height as compared to the currently chosen building.
  • Now, the problem gets reduced to finding the minimum and maximum indices on the right for every building in the sorted array.

Below is the implementation of the above approach:

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation of the above approach
import java.util.Arrays;
  
// Class to store the pairs
class Pair implements Comparable<Pair> {
    int ind, val;
  
    Pair(int ind, int val)
    {
        this.ind = ind;
        this.val = val;
    }
  
    @Override
    public int compareTo(Pair o)
    {
        if (this.val > o.val)
            return 1;
        return -1;
    }
}
  
class GFG {
  
    // Return the maximum water that can be stored
    static int maxWater(int height[], int n)
    {
  
        // Make pairs with indices
        Pair pairs[] = new Pair[n];
        for (int i = 0; i < n; i++)
            pairs[i] = new Pair(i, height[i]);
  
        // Sort array based on heights
        Arrays.sort(pairs);
  
        // To store the min and max index so far
        // from the right
        int minIndSoFar = pairs[n - 1].ind;
        int maxIndSoFar = pairs[n - 1].ind;
        int max = 0;
        for (int i = n - 2; i >= 0; i--) {
  
            // Current building paired with the building
            // greater in height and on the extreme left
            int left = 0;
            if (minIndSoFar < pairs[i].ind) {
                left = (pairs[i].val * (pairs[i].ind - minIndSoFar - 1));
            }
  
            // Current building paired with the building
            // greater in height and on the extreme right
            int right = 0;
            if (maxIndSoFar > pairs[i].ind) {
                right = (pairs[i].val * (maxIndSoFar - pairs[i].ind - 1));
            }
  
            // Maximum so far
            max = Math.max(left, Math.max(right, max));
  
            // Update the maximum and minimum so far
            minIndSoFar = Math.min(minIndSoFar,
                                   pairs[i].ind);
            maxIndSoFar = Math.max(maxIndSoFar,
                                   pairs[i].ind);
        }
  
        return max;
    }
  
    // Driver code
    public static void main(String[] args)
    {
        int height[] = { 2, 1, 3, 4, 6, 5 };
        int n = height.length;
  
        System.out.print(maxWater(height, n));
    }
}

chevron_right


Output:

8

Time Complexity : O(N*log(N)).

Two pointer approach: Take two pointers i and j pointing to the first and the last building respectively and calculate the water that can be stored between these two buildings. Now increment i if height[i] < height[j] else decrement j. This is because the water that can be trapped is dependent on the height of the small building and moving from the greater height building will just reduce the amount of water instead of maximizing it. In the end, print the maximum amount of water calculated so far.

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation of the approach
#include<bits/stdc++.h>
using namespace std;
  
// Return the maximum water that can be stored
int maxWater(int height[], int n)
{
  
    // To store the maximum water so far
    int maximum = 0;
  
    // Both the pointers are pointing at the first
    // and the last buildings respectively
    int i = 0, j = n - 1;
  
    // While the water can be stored between
    // the currently chosen buildings
    while (i < j)
    {
  
        // Update maximum water so far and increment i
        if (height[i] < height[j])
        {
            maximum = max(maximum, (j - i - 1) * height[i]);
            i++;
        }
  
        // Update maximum water so far and decrement j
        else if (height[j] < height[i]) 
        {
            maximum = max(maximum, (j - i - 1) * height[j]);
            j--;
        }
  
        // Any of the pointers can be updated (or both)
        else
        {
            maximum = max(maximum, (j - i - 1) * height[i]);
            i++;
            j--;
        }
    }
  
    return maximum;
}
  
  
// Driver code
int main()
{
  
    int height[] = { 2, 1, 3, 4, 6, 5 };
  
    int n = sizeof(height)/sizeof(height[0]);
  
    cout<<(maxWater(height, n));
}
  
// This code is contributed by CrazyPro

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation of the approach
import java.util.Arrays;
  
class GFG {
  
    // Return the maximum water that can be stored
    static int maxWater(int height[], int n)
    {
  
        // To store the maximum water so far
        int max = 0;
  
        // Both the pointers are pointing at the first
        // and the last buildings respectively
        int i = 0, j = n - 1;
  
        // While the water can be stored between
        // the currently chosen buildings
        while (i < j) {
  
            // Update maximum water so far and increment i
            if (height[i] < height[j]) {
                max = Math.max(max, (j - i - 1) * height[i]);
                i++;
            }
  
            // Update maximum water so far and decrement j
            else if (height[j] < height[i]) {
                max = Math.max(max, (j - i - 1) * height[j]);
                j--;
            }
  
            // Any of the pointers can be updated (or both)
            else {
                max = Math.max(max, (j - i - 1) * height[i]);
                i++;
                j--;
            }
        }
  
        return max;
    }
  
    // Driver code
    public static void main(String[] args)
    {
        int height[] = { 2, 1, 3, 4, 6, 5 };
        int n = height.length;
  
        System.out.print(maxWater(height, n));
    }
}

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 implementation of the approach
  
# Return the maximum water that can be stored
def maxWater(height, n):
  
    # To store the maximum water so far
    maximum = 0;
  
    # Both the pointers are pointing at the first
    # and the last buildings respectively
    i = 0
    j = n - 1
  
    # While the water can be stored between
    # the currently chosen buildings
    while (i < j):
      
        # Update maximum water so far and increment i
        if (height[i] < height[j]):     
            maximum = max(maximum, (j - i - 1) * height[i]);
            i += 1;
          
        # Update maximum water so far and decrement j
        elif (height[j] < height[i]):
            maximum = max(maximum, (j - i - 1) * height[j]);
            j -= 1;
          
        # Any of the pointers can be updated (or both)
        else:     
            maximum = max(maximum, (j - i - 1) * height[i]);
            i += 1;
            j -= 1;
          
    return maximum;
  
# Driver code
height = [2, 1, 3, 4, 6, 5]
  
n = len(height)
  
print (maxWater(height, n));
  
# This code is contributed by CrazyPro

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# implementation of the approach
using System;
  
class GFG
{
      
    // Return the maximum water that can be stored
    static int maxWater(int []height, int n)
    {
  
        // To store the maximum water so far
        int max = 0;
  
        // Both the pointers are pointing at the first
        // and the last buildings respectively
        int i = 0, j = n - 1;
  
        // While the water can be stored between
        // the currently chosen buildings
        while (i < j)
        {
  
            // Update maximum water so far and increment i
            if (height[i] < height[j])
            {
                max = Math.Max(max, (j - i - 1) * height[i]);
                i++;
            }
  
            // Update maximum water so far and decrement j
            else if (height[j] < height[i])
            {
                max = Math.Max(max, (j - i - 1) * height[j]);
                j--;
            }
  
            // Any of the pointers can be updated (or both)
            else 
            {
                max = Math.Max(max, (j - i - 1) * height[i]);
                i++;
                j--;
            }
        }
  
        return max;
    }
  
    // Driver code
    static public void Main ()
    {
          
        int []height = { 2, 1, 3, 4, 6, 5 };
        int n = height.Length;
  
        Console.Write(maxWater(height, n));
    }
}
  
// This code is contributed by jit_t

chevron_right


Output:

8

Time Complexity: O(N)



My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.



Improved By : jit_t, AnkitRai01, ihritik, gp6, CrazyPro