原题目:
Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container.
在X轴有很多垂直的线段,线段长度分别为a1,a2,a3......an,在任意两条线和X轴之间形成一个面积,求能够形成的最大面积。
这里面有一个短板的问题,对于任意两条线ia,ib我们可以得出一个公式S = Math.abs((ia-ib))*Math.min(height[ia],height[ib]).
算法分析:
算法1:遍历法
用两层for循环,从头开始依次向后扫面,每次扫描到的两条线求面积,通过比较求出最大面积。缺点:双层for循环的时间复杂度为O(n^2),在LeetCode提交时因为超时而无法通过。
算法2:
从前后两边同时搜索,短板的那一侧往里走,以为往里走,代表宽度减小,那么宽度减小的时候,只有遇上了更高的高度才能组成更大的面积。所以依次从两侧往里走,直到两条线相遇。
算法3: 6的飞起!
设置两个指针i, j, 一头一尾, 相向而行. 假设i指向的挡板较低, j指向的挡板较高(height[i] < height[j]).
下一步移动哪个指针?
-- 若移动j, 无论height[j-1]是何种高度, 形成的面积都小于之前的面积.
-- 若移动i, 若height[i+1] <= height[i], 面积一定缩小; 但若height[i+1] > height[i], 面积则有可能增大.
综上, 应该移动指向较低挡板的那个指针.
LeetCode提交源码:
算法2:
public int maxArea(int[] height) {
if(height == null || height.length < 2){
return 0;
}
int maxarea = 0;
int left = 0;
int right = height.length-1;
while(left < right){
maxarea = Math.max(maxarea, (right - left) * Math.min(height[left], height[right]));
if(height[left] < height[right]){
left++;
}
else{
right--;
}
}
return maxarea;
}
算法3:
public int maxArea(int[] height) {
if (height==null || height.length==0) { return 0; }
int max = 0;
int i = 0, j = height.length-1;
while (i < j) {
max = Math.max(max, (j-i) * Math.min(height[i], height[j]));
if (height[i] < height[j]) { // should move i
int k; for (k=i+1; k<j && height[k]<=height[i]; ++k) {}
i = k;
} else { // should move j
int k; for (k=j-1; k>i && height[k]<=height[j]; --k) {}
j = k;
}
}
return max;
}
完整运行程序:
/**************************************************************
* Copyright (c) 2016
* All rights reserved.
* 版 本 号:v1.0
* 题目描述: Container With Most Water
* Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai).
* n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0).
* Find two lines, which together with x-axis forms a container, such that the container contains the most water.
* Note: You may not slant the container.
* 输入描述:请输入整数一个数组,以空格隔开
* 5 9 6 37 5 8 2 6 3 9
* 程序输出:算法2:最大面积是:
* 72
* 算法3:最大面积是:
* 72
* 问题分析:双层for循环,时间复杂度较大
* 算法描述:算法1:遍历法,用两层for循环,从头开始依次向后扫面,每次扫描到的两条线求面积,
* 通过比较求出最大面积。缺点:双层for循环的时间复杂度为O(n^2),在LeetCode提交时因为超时而无法通过。
* 算法2:
* 从前后两边同时搜索,短板的那一侧往里走,以为往里走,代表宽度减小,那么宽度减小的时候,
* 只有遇上了更高的高度才能组成更大的面积。所以依次从两侧往里走,直到两条线相遇。
* 算法3: 6的飞起!
* 设置两个指针i, j, 一头一尾, 相向而行. 假设i指向的挡板较低, j指向的挡板较高(height[i] < height[j]).
* 下一步移动哪个指针?
* -- 若移动j, 无论height[j-1]是何种高度, 形成的面积都小于之前的面积.
* -- 若移动i, 若height[i+1] <= height[i], 面积一定缩小; 但若height[i+1] > height[i], 面积则有可能增大.
* 综上, 应该移动指向较低挡板的那个指针.————摘自LeetCode大神
* 完成时间:2016-11-24
***************************************************************/
package org.GuoGuoFighting.LeetCode011;
import java.util.Scanner;
/*
* 算法1:双层for循环,时间复杂度较大,对于大量数据输入会导致超出时间限制,
*/
class SolutionMethod1{
public int maxArea(int[] height){
if(height == null || height.length < 0){
return -1;
}
if(height.length == 1){
return 0;
}
int sqrt = 0;
// int i = 1;
// int j = 2;
//int reuslt = 0;
int tmp;
for(int i = 1; i <= height.length; i++){
for(int j = i + 1;j <= height.length; j++){
if(height[j] > height[i]){
tmp = Math.abs(j-i)*height[i];
//System.out.println("tmp= " + tmp + ",i = " + i + ",j=" +j);
if(sqrt < tmp){
sqrt = tmp;
}
}
// tmp= Math.abs(j-i)*Math.min(height[i-1],height[j-1]);
}
}
return sqrt;
}
}
class SolutionMethod2{
public int maxArea(int[] height) {
if(height == null || height.length < 2){
return 0;
}
int maxarea = 0;
int left = 0;
int right = height.length-1;
while(left < right){
maxarea = Math.max(maxarea, (right - left) * Math.min(height[left], height[right]));
if(height[left] < height[right]){
left++;
}
else{
right--;
}
}
return maxarea;
}
}
/*算法3:6的飞起啊!
设置两个指针i, j, 一头一尾, 相向而行. 假设i指向的挡板较低, j指向的挡板较高(height[i] < height[j]).
下一步移动哪个指针?
-- 若移动j, 无论height[j-1]是何种高度, 形成的面积都小于之前的面积.
-- 若移动i, 若height[i+1] <= height[i], 面积一定缩小; 但若height[i+1] > height[i], 面积则有可能增大.
综上, 应该移动指向较低挡板的那个指针.
*/
class SolutionMethod3 {
public int maxArea(int[] height) {
if (height==null || height.length==0) { return 0; }
int max = 0;
int i = 0, j = height.length-1;
while (i < j) {
max = Math.max(max, (j-i) * Math.min(height[i], height[j]));
if (height[i] < height[j]) { // should move i
int k; for (k=i+1; k<j && height[k]<=height[i]; ++k) {}
i = k;
} else { // should move j
int k; for (k=j-1; k>i && height[k]<=height[j]; --k) {}
j = k;
}
}
return max;
}
}
public class ContainerWithMostWater {
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
System.out.println("请输入整数一个数组,以空格隔开");
String str = scanner.nextLine();
String[] tmp = str.split(" ");
int[] array = new int[tmp.length];
for(int i = 0;i < array.length; i++){
array[i] = Integer.parseInt(tmp[i]);
}
scanner.close();
// SolutionMethod1 solution1 = new SolutionMethod1();
// System.out.println("算法1:最大面积是:");
// System.out.println(solution1.maxArea(array));
SolutionMethod2 solution2 = new SolutionMethod2();
System.out.println("算法2:最大面积是:");
System.out.println(solution2.maxArea(array));
SolutionMethod3 solution3 = new SolutionMethod3();
System.out.println("算法3:最大面积是:");
System.out.println(solution3.maxArea(array));
}
}
程序运行结果: