zoukankan      html  css  js  c++  java
  • Leetcode 11

    题目描述

    给你 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) {
            final int length = height.length;
            int first = 0;
            int last = length - 1;
            int maxArea = Math.min(height[first], height[last]) * (last - first);
    
            for (int i = 0; i < length; i++) {
                if (first == last) {
                    break;
                } else if (height[first] <= height[last]) {
                    first++;
                } else if (height[first] > height[last]) {
                    last--;
                }
    
                maxArea = Math.max(maxArea, Math.min(height[first], height[last]) * (last - first));
            }
            return maxArea;
        }
    }
    

    执行用时: 5 ms , 在所有 Java 提交中击败了 45.35% 的用户

    内存消耗: 40.1 MB , 在所有 Java 提交中击败了 21.43% 的用户

    题解反思

    这道题采用 “双指针” 的思路。用 firstlast 分别代表长方形的两边,初始值分别为 0length-1

    • 分别用一个指针标识整个长方形的两边,这两个指针所对应的数组索引之差就是长方形的底边,这时整个长方形的面积为:Math.min(height[first], height[last]) * (last - first),并用 maxArea 记录最大的面积。
    • 将整个长方形逐渐向中间趋近,以防止漏掉中间有较大的长边。这时我们分别比较 height[first]height[last] 的值,也即这个长方形左右两边的高,若左边较低,就将左指针右移(first++),若右边较低,就将右指针左移(last--)。
    • 左右指针移动之后,便再次计算当前长方形的面积(Math.min(height[first], height[last]) * (last - first))。
    • 并将该面积和 MaxArea 中保存的值作对比,以将当前较大的面积保存在 MaxArea 变量中。
    • 当左指针和右指针相遇时,即 first == last,就终止数组的循环,此时 MaxArea 中保存的即为最大面积。

    复杂度分析

    • 时间复杂度:O(n),双指针最多遍历整个数组一次。
    • 空间复杂度:O(1),无需额外的空间开销,只需存储左右指针和最大面积的值即可。

    优化

    虽然按照自己的题解是能够通过所有的测试用例的,但是看了评论区的一些解答,发现在代码的可读性上还是可以优化的。

    在循环时,自己采用的是 for (int i = 0; i < length; i++) 而将循环中断的条件放在了循环体中,即:if (first == last) { break; }

    想一下,如果将循环中断的条件放在循环的声明中,并采用 while 循环,整个代码看起来就会更加可读一些,如下:

    public int maxArea(int[] height) {
            final int length = height.length;
            int first = 0;
            int last = length - 1;
            int maxArea = Math.min(height[first], height[last]) * (last - first);
            
            while(first < last){
                if (height[first] <= height[last]) {
                    first++;
                } else if (height[first] > height[last]) {
                    last--;
                }
                maxArea = Math.max(maxArea, Math.min(height[first], height[last]) * (last - first));
            }
            return maxArea;
    }
    

    这样就会比之前采用 for i 循环看起来更优雅也更易读一些,且更清楚的表达了自己的解题逻辑。

    本文首发于「愚一笔记」。

  • 相关阅读:
    win7下new出的内存默认是无执行权限的
    【转】 C++获得系统时间,以及1970年1月1日到现在的毫秒数
    【收藏】获取系统安装软件(vc++源码)
    opencv编译以及测试
    Vim命令合集
    在SSMS中打开DTS Package
    秋日的阳光
    又一位部门同事离职
    不要让你的孩子成为留守儿童,更不让你的父母成为空巢老人
    又将有一位同事离职
  • 原文地址:https://www.cnblogs.com/foolaris/p/12766869.html
Copyright © 2011-2022 走看看