当前位置:   article > 正文

LeetCode第十一题: 盛最多水的容器 (Java)_盛最多水的容器 java

盛最多水的容器 java

题目:字符串转换整数

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

示例:

  1. 输入:[1,8,6,2,5,4,8,3,7]
  2. 输出:49
  3. 解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49
  4. 输入:height = [1,1]
  5. 输出:1

题目解读:

当时读题目的时候也没明白什么意思,看了示例1的图片明白了。

容纳最多的水,是由有两条垂线中较短的一根垂线 与 两条垂线的距离决定。

换成数学语言来说,即求 蓝色区域的面积。设两条垂线对应的坐标是x = i,x = j。长度为h[i], h[j]。蓝色区域面积为 min(h[i],h[j]) * ( j - i )

第一想法求出所有两条垂线所组成的面积。然后找办法优化,当时想法既然面积只由较短的垂线和两条垂线的距离决定,那么我只要固定一条垂线,找到比这条垂线高且距离最远,那么就是当前固定的这条垂线所能构成最大的蓝色区域面积(即容纳最多的水)。

举个例子:i 是那条固定的较小的垂线,蓝色区域则是它所能构成的最大蓝色区域。要保证 i 是较小的那条。比求出所有的面积可以筛掉一些结果。

 但是写代码时发现了一些问题,我是从后向前找比固定的那根垂线长的垂线,比如倒数第三根垂线。他所构成最大面积是蓝色而不是红色区域。这种情况没考虑到两条垂线距离最大,后来我想到的解决办法是,每次循环在固定垂线左右两边找到比固定垂线长且距离最大的垂线。

 方法一:自己分析出来的

在暴力循环求出所有两条垂线容纳的水基础上,想通过一些条件减少循环,实际上好像并没比暴力循环优化多少。

  1. //把 height[i] 当作较短的,找比他高的 且 距离最长 计算面积
  2. public static int maxArea(int[] height) {
  3. //存放最大值
  4. int max = 0;
  5. //当前循环的最大值 即左右两边比较
  6. int max1 = 0;
  7. int len = 0;
  8. // 固定垂线 右边 比固定垂线长 的 两条垂线的距离
  9. int len1 = 0;
  10. //固定垂线 左边 比固定垂线长 的 两条垂线的距离
  11. int len2 = 0;
  12. for (int i = 0; i < height.length; i++) {
  13. int end = height.length - 1;
  14. int start = 0;
  15. //固定垂线右边,从最后一根循环
  16. while (height[i] > height[end] && end > i) {
  17. end--;
  18. }
  19. len1 = end - i;
  20. //固定垂线左边,从第一根循环
  21. while (height[i] > height[start] && start < i) {
  22. start++;
  23. }
  24. len2 = i - start;
  25. //比较左右两边,最长距离
  26. len = (len1 > len2) ? len1 : len2;
  27. max1 = len * height[i];
  28. max = (max > max1) ? max : max1;
  29. }
  30. return max;
  31. }

写文章时发现,可以再稍微优化一下。当 i 超过length一半时,优先找左边符合条件的垂线。当找比 height[i] 长且  i - start > length - i  ,那么不需要再执行右边找符合条件垂线的循环。这种思路还是有点问题,加上这个优化也快不了多少。

方法二:官方双指针

两条垂线作为左右指针,每次循环移动长度较小的垂线,计算面积和比较,存储最大面积。因为所容纳最多的水是由较小的垂线决定。

  1. //双指针 每次循环扔掉较小的
  2. public static int maxArea2(int[] height) {
  3. int start = 0;
  4. int end = height.length - 1;
  5. int max = 0;
  6. while (start < end) {
  7. if (height[start] < height[end]) {
  8. max = (max > height[start] * (end - start)) ? max : height[start] * (end - start);
  9. start++;
  10. } else {
  11. max = (max > height[end] * (end - start)) ? max : height[end] * (end - start);
  12. end--;
  13. }
  14. }
  15. return max;
  16. }

相比我自己的想法,他相当于每次把较小的一个垂线计算完,就让掉了,不再参与后面循环,优化更大。

方法三:评论区看到的方法

评论区看到的,感觉也肯巧妙。他把 height[i] 当作固定的。我们每次循环都存储到当前最大面积,较小垂线长度 = 面积 / 边长(即两条垂线的距离),当前循环最大边长为 lengh-1-i (最后一根垂线不在用循环,他右边没有垂线了)。当 max / lengh-1-i > hight[ i ]时,表示当前循环的 height[i] 比 目前存储最大面积所需要的最小垂线还短,所以他一定不是符合条件的垂线,他不再需要进入循环面积比较。

  1. public static int maxArea(int[] height) {
  2. int len = height.length;
  3. int max = 0, water = 0;
  4. for(int i = 0 ; i < len - 1; i++){
  5. // 每次循环左边固定height[i]
  6. //max / (len-i-1) 最大面积是,需要最小边的高。此时长度是最大,height[i]比需要最大面积最小边还小
  7. if(height[i] > max / (len-i-1)){
  8. //面积比较
  9. for(int j = i + 1; j < len; j++){
  10. water = (j-i) * Math.min(height[i], height[j]);
  11. if(max < water)
  12. max = water;
  13. }
  14. }
  15. }
  16. return max;
  17. }

总结:

这道题感觉并不难,再不济求出所有的面积进行比较。

做这道题时感觉很像小学时做的应用题,可以用很多办法解决问题,最后都可以得出答案。例如这道题的双指针,双指针单拿出来谁都会,但是应有到具体的问题上却想不起来。

最后做题不单单是为了最后得出答案,而是扩展思路,多种方法解决问题,这样面对其他类似的题目可以找到最优的解决办法

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/146221
推荐阅读
相关标签
  

闽ICP备14008679号