给定 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 i = 0;
int j = height.length - 1;
int max = 0;
while(i < j) {
int area = (j - i) * Math.min(height[i], height[j]);
if(area > max)
max = area;
if(height[i] <= height[j])
++i;
else if(height[j] < height[i])
--j;
else
break;
}
return max;
}
}
变形:容器储水问题
给定一个大小为n的水池组,求水池最多能蓄水多少
例:第一行输入n=5
第二行输入n个值[5,2,1,4,3]
输出:5
思路分析:
(1)很容易先想到暴力求解:
a.遍历数组的每个位置,分别依次求出当前位置左侧的最大值和右侧的最大值
b.当前位置,容器能够储存的水量为Math.max( 0, Math.min(left,right)-arr[i] ),也就是当前位置的左右侧的最小值减去当前位 置的储水量。
c.最后遍历每个位置,求出每个位置的储水量,相加即为总储水量。
时间复杂度O(N^2)
(2)但由于暴力解决时间复杂度过高,故在此采用指针的方式,来更新左右最大值。节省时间和空间。
package com.cn.java.niuke;
import java.util.Scanner;
/*
* 水池储水问题
* 输入:5 2 1 4 3
* 输出:5*/
public class test{
public static void main(String[] args) {
//数组大小n
Scanner in = new Scanner(System.in);
int n = in.nextInt();
//定义水池
int[] pool = new int[n];
for(int i = 0;i<pool.length;i++) {
pool[i]=in.nextInt();
}
System.out.println(findValue(pool));
}
private static int findValue(int[] pool) {
if(pool==null || pool.length<3) {
return 0;
}
int leftmax=pool[0];//找到左边最大的一个
int rightmax=pool[pool.length-1];//找到右边最大的一个
int value=0;//总容量
int l=1;//左指针
int r=pool.length-2;//右指针
while(l<=r) {
if(leftmax <rightmax) {
value += Math.max(leftmax-pool[l], 0);
leftmax = Math.max(leftmax, pool[l++]);
}else {
value += Math.max(rightmax-pool[r], 0);
rightmax = Math.max(rightmax, pool[r--]);
}
}
return value;
}
}
结果:
5
5 2 1 4 3
5