Leetcode 11 - 盛最多水的容器(题目与思考)

题目

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

 

样例:

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

题目理解

  1. 本题是一道高频面试题,根据题意不难求出,计算接雨水面积的公式为  底边长度 * 高度 ,设 i 为左指针,j 为右指针,则可知面积计算公式为 (j - i) * min(nums[j],nums[i])
  2. 由上可得,最朴素的思路是使用双重循环暴力求解,即遍历所有可能的组合并计算长度。时间复杂度O(N*2),空间复杂度O(1),显然这不是最优解
  3. 为了优化算法,让我们回归问题的本质。此类寻找  某个最优区间的问题  很容易让人想到类似  sliding window  的解法。那么下一个问题就是,如何进行窗口的滑动。
  4. 不难想到,在滑动的过程中,无论是左指针 i ++  或是 右指针 j -- 底边长度都会减1,故只有优化高度,即在每次移动中,都试图寻找使高度更大的选项,也就是移动左右两边长度较短的那一边
  5. 由此,只需将 i 设定为 0 ,j 设定为 nums.length - 1,如果左高度 nums[ i ] < nums[ j ] 则移动左指针 i ++ ;如果右高度 nums[ j ] < nums[ i ] 则移动右指针  j -- ,并记录每次的面积。 仅需一次遍历,时间复杂度为O(N)

 

代码:

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

 

思考与拓展

  1.滑动窗口题目最关键的步骤在于如何确定滑动的方式以及如何确定初始状态(避免漏解),关于滑动方式,其实就是每一步如何保证局部最优解的问题,关于避免漏解或错解,请看与本题类似的LeetCode 448题的分析。

posted @ 2020-04-18 22:19  Jiangzhuoan  阅读(132)  评论(0)    收藏  举报