zoukankan      html  css  js  c++  java
  • 算法--------数组--------容纳最多的水

    给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和
     (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
    
    说明:你不能倾斜容器,且 n 的值至少为 2。
    
    
    

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

    示例:

    输入: [1,8,6,2,5,4,8,3,7]
    输出: 49

    我的解答:

    class Solution {
        public int maxArea(int[] height) {
               int length = height.length;
            if (length == 0) {
                return 0;
            }else if (length == 1){
                return height[0];
            }
    
            int max = 0;
            for (int i =0, j =length -1; j > i ;  ){
                int minHeight = Math.min(height[i], height[j]);
                max = Math.max(max,minHeight * (j -i));
                if (height[i] > height[j]) {
                    j--;
                }else {
                    i++;
                }
            }
            return max;
        }
    }
    

    看到网上优化过的之后:

    class Solution {
        public int maxArea(int[] height) {
            int length = height.length;
            if (length == 0) {
                return 0;
            }else if (length == 1){
                return height[0];
            }
    
            int max = 0;
            for (int i =0, j =length -1; j > i ;  ){
                int start = height[i];
                int end = height[j];
                int minHeight = Math.min(start, end);
                max = Math.max(max,minHeight * (j -i));
    //            if (start > end) {
    //                while (height[--j]<end && j> i);
    //            }else {
    //                while (height[++i]<end && j> i);
    //            }
    
                            if (start > end) {
                    do {
                        j--;
                    }while (height[j]<end && j> i);
                }else {
                    do {
                        i++;
                    }while (height[i]<start && j> i);
                }
            }
            return max;
        }
    }
    

    下面分析下解题思路:

    双索引,左右开弓。第一次遍历的肯定是左右两边的两个数。这时候,比较两个数,放弃比较小的那个数,继续遍历。为什么可以放过最小的那个数呢?
    比如说左边的数,比右边的数小,那么对于左边那个数来说,他存在最大的值,就是最右边那个。因为对于左边那个数来说,和其他任何位置的组合,都没有最右边那个数大,所以,对于左边那个小的数,可以不用再遍历。一定是最大的组合。那么,这个数就可以不用遍历了。以此类推。时间复杂度是O(n);

    依次类推可以得到每一个数和其他数组合的最大值。然后得出最大值就可以了。

    总结:

    1.看到别人的算法,总是可以让自己学到点什么。
    2.解题思路很重要。思考问题的方式很重要。

    解决过程:

    刚开始,我做题的时候,同事在旁边,给我说了思路,左右遍历,然后小的数扔掉。当时,我担心的是,这样的话,会不会错失掉最大值?因为有些情况没有遍历,后来,我去尝试推翻同事的解法,后来发现,他是对的。思路就是上面我写的。嗯,我觉得,对任何人说的,都应该质疑,推翻,这会让你印象更深刻。这才有学习的意义。才有意思。

  • 相关阅读:
    远程诊断DoIP
    基于linux内核包过滤技术的应用网关
    Boost内存池使用与测试
    C++ 编程规范
    大象——Thinking in UML
    C++ 创建类时常考虑的问题
    SLIP—串行线路上传输数据报的非标准协议
    神秘的程序员——编程的乐趣
    Bad Smell (代码的坏味道)
    模式与软件架构——软件架构的非功能特征
  • 原文地址:https://www.cnblogs.com/caoxinyu/p/10568509.html
Copyright © 2011-2022 走看看