Leetcode 11: Container With Most Water
Kardel Chen
Posted on June 6, 2021
Problem:
Problem Statement
Given n non-negative integers a1, a2, ..., an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of the line i is at (i, ai) and (i, 0). Find two lines, which, together with the x-axis forms a container, such that the container contains the most water.
Notice that you may not slant the container.
Example 1:
Input: height = [1,8,6,2,5,4,8,3,7]
Output: 49
Explanation: The above vertical lines are represented by >array [1,8,6,2,5,4,8,3,7]. In this case, the max area of >water (blue section) the container can contain is 49.
Example 2:
Input: height = [1, 1]
Output: 1
Example 3:
Input: height = [4,3,2,1,4]
Output: 16
Example 4:
Input: height = [1,2,1]
Output: 2
Constraints:
n == height.length
2 <= n <= 105
0 <= height[i] <= 104
Thinking and Solutions:
Well, I thought since this is a Dynamic Programming problem, we can create a recursion function.
And matrix is a 2 dimension matrix and matrix[i][j] store the maximal area from the i-th index to j-th index.
Then I want to find the maximal area among matrix[i][j-1], matrix[i+1][j] and matrix[i]j.
public class Solution {
public static int maxArea(int[] height) {
// Using Dynamic Programming
// This is the area matrix. The first index is the start index. The second index is the ending index.
int[][] matrix = new int[height.length][height.length];
for (int i = 0; i < height.length; i++) {
for (int j = 0; j < height.length; j++) {
matrix[i][j] = -1;
}
}
return maxAreaSub(height, 0, height.length-1, matrix);
}
public static int maxAreaSub(int[] height, int starting, int ending, int[][] matrix) {
if(matrix[starting][ending] != -1){
return matrix[starting][ending];
}
if (ending - starting == 1) {
return Math.min(height[ending], height[starting]);
}
int left = maxAreaSub(height, starting, ending - 1, matrix);
int right = maxAreaSub(height, starting + 1, ending, matrix);
int current = (ending - starting) * Math.min(height[ending], height[starting]);
int maxV = Math.max(Math.max(left, current), right);
matrix[starting][ending] = maxV;
return maxV;
}
}
But a problem was that if the list is very long, like 1000 elements in the list, the matrix is 4M ($4 \time 1000 \time 1000$) for integer matrices.
So I thought building the dynamic programming from bottom to top could be a better way because it is more reasonable. Also, you don't need to store the maximal area matrix. Instead, storing the maximal area list for a certain length could be a good idea to reduce the storage pressure.
public class Solution2 {
public static int maxArea(int[] height) {
// Using Dynamic Programming
// This is the area matrix. The first index is the start index. The second index is the ending index.
int[] miniArea = new int[height.length];
for (int i = 0; i < height.length; i++) {
miniArea[i] = 0;
}
return maxAreaSub(height, 1, miniArea);
}
public static int maxAreaSub(int[] height, int length, int[] miniArea) {
int[] areas = new int[height.length - length];
for (int i = 0; i < height.length - length; i++) {
int left = miniArea[i];
int right = miniArea[i + 1];
int current = length * Math.min(height[i], height[i + length]);
areas[i] = Math.max(current, Math.max(left, right));
}
if (areas.length == 1) {
return areas[0];
}
return maxAreaSub(height, length + 1, areas);
}
}
The storage problem seems to be solved but actually since the recursion function is still too slow, time limit is still exceeded. So here, I sought for others' solutions. This is much easier solution but it seems to work well.
class Solution {
public int maxArea(int[] height) {
int left = 0;
int right = height.length - 1;
int maxArea = 0;
while(left < right) {
maxArea = Math.max(maxArea, Math.min(height[left], height[right]) * (right - left));
if(height[left] <= height[right]) {
left++;
} else {
right--;
}
}
return maxArea;
}
}
It uses a global maximal area. With 2 pointers right and left, we can find a local area and judge which is the current maximal area.
Also, it has a basic idea that the maximal area is from the maximal length or from shorter length with two higher heights. So just greedy search the longer 2 heights could reduce the running time.
Conclusion
According to the problem, I realize 2 things:
- Reasonable greedy search could be a good way to reduce the running time.
- Writing a
while
instead of using a recursion function could be a good way for running dynamic programming.
Posted on June 6, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
September 27, 2024