每天一道算法题——盛最多水的容器

题目
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器。
示例1
在这里插入图片描述

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/container-with-most-water

先讲一下我自己的暴力把,毕竟脑壳瓜子 有灵光一闪的时候。
暴力求解思路
首先坐标(i,ai),其中i表示数组中索引,ai表示索引对应的值
i和j分别代表两个索引位置,j-i为第一条线,height[i]或height[j]为第二条线
其中,当height[i]>height[j]时,第二条线为height[j],否则为height[i],这是因为
第二条线只能取两个值中小的那一个(木桶原理:水只能装到板最短的那块)。
算法步骤

1.input : int [] height, int i=0, int j=i+1,int tempArea=0, int area;
2.output : area;
3.tempArea=min(height[i], height[j])*(j-i),判断tempArea是否大于area,如果是,转至4,否则,转至5;
4.area=tempArea, j=j+1, 如果j<height.length, 转至3, 否则,转至6;
5.j=j+1,如果j<height.length, 转至3, 否则,转至6;
6. i=i+1, j=i+1, 转至3; 如果i=height.length-2, 转至7;
7. return area.

写完了渣渣算法,那就来实现一下。

 public int maxArea(int[] height) {
    
    
        int area=0;
        for(int i=0;i<height.length;i++){
    
    
            for(int j=i+1;j<height.length;j++){
    
    
                if(height[i]<height[j]){
    
      
                    int temp=height[i]*(j-i); //暂存计算结果
                    area=(area<temp)?temp:area; 
                }else if(height[i]>height[j]){
    
    
                    int temp=height[j]*(j-i);
                    area=(area<temp)?temp:area; 
                }else{
    
    
                    int temp=height[i]*(j-i);
                    area=(area<temp)?temp:area; 
                }
            }
        }
        return area;
    }

运行时间是1042ms,空间复杂度是O(n^2)。
看到这么菜的实现,我肯定是忍不了的,那肯定有好办法去解决它,虽然现在不能一次性想到,但是在通往一次性想到的路上。
下面是参考leetcode官方解答思路,正正宗宗的双指针。
首先令first=0, last=height.lenght-1;头指针放在数组的第一个位置,尾指针放在数组的最后一个位置。然后,计算两个位置的容器面积area,然后移动较小元素的指针(这里同样是木桶原理,装水只能装到最短的那块板),计算移动后的指针面积,比较两次面积大小,取最大的。当first和last指向同一个位置时,返回area。
本着知其然知其所以然的道理,我把它写成算法

  1. input : int[]height , int first=0, int last=height.length-1, int area;
  2. output: area;
  3. 判断last>first,为真,转至4,否则转至7;
  4. 计算int tempArea=min(height[first],height[last])*(last-first),area=max(tempArea,area);判断height[first]>height[last],为真,转至5,否则转至6;
    5.last=last-1,转至3;
  5. first=first+1,转至3;
  6. return area;

根据这个算法,java实现如下:

 public int maxArea(int[] height) {
    
    
         int first=0;
         int last=height.length-1;
         int area=0;
         while(first<last){
    
    
            if(height[first]<=height[last]){
    
    
                int temp=height[first]*(last-first);
                area = (area<temp)?temp:area;
                first++;
            } else {
    
    
                int temp=height[last]*(last-first);
                area=(area<temp)?temp:area;
                last--;
            }
         }
         return area;
     }

运行时间3ms,时间复杂度O(n),哇,what can i say? do it!!
这里还有一个问题,那就是得证明这个方法求出的一定是最大值

给大家指一条明路:

https://leetcode-cn.com/problems/container-with-most-water/solution/sheng-zui-duo-shui-de-rong-qi-by-leetcode-solution/

猜你喜欢

转载自blog.csdn.net/weixin_43763175/article/details/109527750