11.盛最多水的容器
解题思路:
package leadcode;
/**
* @author : icehill
* @description : 盛最多水的容器
* 给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。
* 在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。
* 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
* <p>
* 来源:力扣(LeetCode)
* 链接:https://leetcode-cn.com/problems/container-with-most-water
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
* 解题思路:
* 1.暴力解法
* 时间复杂度O(n^2)空间复杂度O(1)
* 2.双指针(最优解)
* 这个解法一开始也没想到,只是觉得有点规律,但是没证明
* 分析过程:
* 对于数组[a1,a2,……an],求最大的面积,上面的暴力解法就是对于
* 每种可能进行枚举,然后计算面积,再求最大值,但是实际上有些情况可以不用计算
* 前提:面积计算公式:min(a1,an)*(n-1)
* (1).例如以a1为左边界,a2,a3……an为右边界,求这n-1个可能中的最大值
* 如果a1<=an,那么无论a2,a3……an-1,比a1大还是小,根据面积计算公式,左半边min(a1,ak)<=min(a1,an),而(k-1)必定小于(n-1)
* 所以如果a1<an,则只需要计算a1,an即可,
* 如果a1>an,反过来,对于以an为右边界的所有可能,an*(n-1)最大,其他[a2,……an-1]为左边界的,到右边界an都不需要计算
* 这样相当于每次我们无论移动左指针还是右指针,都能直接节省暴力解法一轮for循环
* (2)接下来就是继续枚举a2为左边界,a3,a4……an,或者a1为做边界,a2,a3……an-1为有边界的所有可能,继续把这剩下的当做一个新的数组,重复(1)的过程
* (3)根据上面的分析规律,我们可以定义双指针,每次移动较小的指针,比较一次,
* 直到两个指针相遇中间所有可能的结果的最大值就是题解
* 时间复杂度O(n)空间复杂度O(1)
* @date : 2021-04-13
*/
public class Solution11 {
public static void main(String[] args) {
Solution11 solution11 = new Solution11();
int[] arr1 = {1, 8, 6, 2, 5, 4, 8, 3, 7};
int[] arr2 = {1, 1};
int[] arr3 = {4, 3, 2, 1, 4};
System.out.println(solution11.maxArea(arr1));
System.out.println(solution11.maxArea(arr2));
System.out.println(solution11.maxArea(arr3));
}
public int maxArea(int[] height) {
//数组长度
int lenght = height.length;
if (lenght < 2) {
return 0;
}
//双指针起始位置
int begin = 0;
int end = height.length - 1;
//记录当前最大面积
int maxArea = 0;
while (begin < end) {
//计算begin end直接的盛水面积(最小边界*两者之间长度)
int currentArea = Math.min(height[begin], height[end]) * (end - begin);
if (currentArea > maxArea) {
maxArea = currentArea;
}
//移动较小值的指针,原因详见解题分析
if (height[begin] <= height[end]) {
begin++;
} else {
end--;
}
}
return maxArea;
}
/**
* 暴力解法
*
* @param height
* @return
*/
public int maxAreaTwo(int[] height) {
//暴力做法
int max = 0;
int min = 0;
for (int i = 0; i < height.length - 1; i++) {
for (int j = i + 1; j < height.length; j++) {
if (height[i] > height[j]) {
min = height[j];
} else {
min = height[i];
}
if (((j - i) * min) > max) {
max = (j - i) * min;
}
}
}
return max;
}
}