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
思路一:暴力双循环
对每个元素都已当前元素为左界,后面的每个元素为右界,分别计算面积的最大值
1 class Solution { 2 public int maxArea(int[] height) { 3 // 暴力双循环 4 // 对每个元素都已当前元素为左界,后面的每个元素为右界,分别计算面积的最大值 5 int maxArea = 0; 6 int n = height.length; 7 for(int i = 0; i < n - 1; i++){ 8 for(int j = i + 1; j < n; j++){ 9 int high = height[i] <= height[j] ? height[i] : height[j];// 高度取矮的那个 10 int area = high * (j-i); 11 maxArea = Math.max(area, maxArea); 12 } 13 } 14 return maxArea; 15 } 16 }
leetcode 执行用时:1022 ms > 5.04%, 内存消耗:40.5 MB > 5.00%, 用了1000+ms, 可见效率有多低
复杂度分析:
时间复杂度:两个循环,所以复杂度为O(n2)
空间复杂度:变量空间都是常量级的,所以空间复杂度为O(1)
思路二:双指针法
参考:
双指针法,两指针分别从左右向里移动,每次都把指向矮的板子的指针向内移动一格,移动之后,虽然底边缩短了,但是高度有可能会增大很多,所以面积有增大的可能性;但是如果把指向长板的指针向内移动一格,因为面积取决于对面的短板高度,所以无论此次移动后得到的更长的板还是更短的板都不能使面积增大,所以只有移动指向矮板的指针才有可能使面积增大。1 class Solution { 2 public int maxArea(int[] height) { 3 4 int len = height.length; 5 int left = 0, right = len-1; 6 int maxArea = 0; 7 while(left < right){ 8 if(height[left] < height[right]){ 9 maxArea = Math.max(maxArea, height[left] * (right - left)); // 如果左板短于右板,左指针向内移一格 10 left++; 11 }else{ 12 maxArea = Math.max(maxArea, height[right] * (right - left)); // 如果右板短于左板,右指针内移一格 13 right--; 14 } 15 } 16 return maxArea; 17 } 18 }
leetcode 执行用时:3 ms > 92.80%, 内存消耗:40.6 MB > 5.00%, 可以看到效率提升不只一星半点。
复杂度分析:
时间复杂度:左右指针加起来一共才对数组遍历了一次,所以时间复杂度为O(n)
空间复杂度:O(1)