标签:
问题描述:Given n non-negative integers a1, a2, ..., an, where each represents a pointat coordinate (i, ai). n vertical lines aredrawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find twolines, which together with x-axis forms a container, such that the containercontains the most water.
Note: You may not slant the container.
问题分析:水桶问题,取决于|i – j|* min(a[i] ~ a[j]),即a[i]到a[j]的最小值乘以距离
代码:
最优解法:类似于TwoSum:http://blog.csdn.net/woliuyunyicai/article/details/44222949
直观的解释是:容积即面积,它受长和高的影响,当长度减小时候,高必须增长才有可能提升面积,所以我们从长度最长时开始递减,然后寻找更高的线来更新候补;
故根据贪心算法,应使i之前的数都比a[i]要小,j之后的数都比a[j]要小;
所以我们从两头向中间靠拢,同时更新候选值;在收缩区间的时候优先从 x, y中较小的边开始收缩。
类似于2Sum的思想,两边设一个指针,然后计算area,如果height[i] <= height[j],那么i++,因为在这里height[i]是瓶颈,j往里移只会减少面积,不会再增加area。
这是一个贪心的策略,每次取两边围栏最矮的一个推进,希望获取更多的水。
一个不严格的证明:
当height[i] <=height[j]时,为什么是i++,而不是j++来获取可能更多的水?
假设j‘ > j,之所以j‘往左移,是因为存在height[i‘] > height[j‘] (i’ <= i), 而那时area‘ = (j‘ - i‘) *min(height[i‘], height[j‘]),
因为height[j‘] ==min(height[i‘], height[j‘]),所以area‘ = (j‘ - i‘) *height[j‘]。而i 和 j‘构成的面积area = (j‘ - i) * min(height[i], height[j‘])。area‘ >= area,所以j不需要往右移。
代码:
public int maxArea(int[] height) { if(height == null || height.length == 0) { return 0; } int i = 0; int j = height.length() - 1; int ret = 0; while(i < j) { int area = (j - i) * Math.min(height[i], height[j]); ret = ret > area ? ret : area; if (height[i] <= height[j]) i++; else j--; } return ret; }
原始解法,时间复杂度O(O^3)
public class Solution { public int maxArea(int[] height) { if(height == null || height.length == 0) { return 0; } int max = 0; for(int j = 1; j < height.length; j++) { int temp_max = 0; for(int i = 0; j + i < height.length; i++) { int temp = MinValue(height, i , j + i); temp_max = temp > temp_max ? temp : temp_max; } max = (temp_max * j) > max ? (temp_max * j) : max; } return max; } //比较数组i-j的最小值 private int MinValue(int[] data, int start , int end) { int min = Integer.MAX_VALUE; for(int i = start; i <= end; i++) { if(min > data[i]) { min = data[i]; } } return min; } }
解法二:改进算法二,时间复杂度O(n^2),空间复杂度O(n)
即使用一个数组,存储上一次循环[i , j -1]的最小值saved_min,此次循环中计算[i,j]最小值,仅需要比较saved_min[i]与height[j]比较得出最小值即可;
public class Solution { public int maxArea(int[] height) { if(height == null || height.length == 0) { return 0; } int max = 0; int[] saved_min = new int[height.length]; for(int j = 1; j < height.length; j++) { int temp_max = 0; for(int i = 0; j + i < height.length; i++) { if(j == 1) { saved_min[i] = MinValue2(height[i],height[i + j]); } else { saved_min[i] = MinValue2(saved_min[i],height[i + j]); } temp_max = saved_min[i] > temp_max ? saved_min[i] : temp_max; } max = (temp_max * j) > max ? (temp_max * j) : max; } return max; } //比较数组i-j的最小值 private int MinValue2(int a , int b) { return a < b ? a : b; } }
leetcode-11 Container With Most Water
标签:
原文地址:http://blog.csdn.net/woliuyunyicai/article/details/44917611