一个非负整数数组a1, a2, …, an 分别代表一系列点 (i, ai),分别过这些点作x轴的垂线,任选两条线与x轴组成一个容器,求容器最大能盛下多少水。要求复杂度O( n )
注:容器不能倾斜;保证n>=2
最容易想到的就是类似冒泡扫一遍过去,复杂度O( n^2 ),TLE
题解
很容易理解的O( n )方法:双指针(Two Pointers)
设选择的两个点为(i, a[i])(j, a[j]),则水量C = (j - i)*min(a[i], a[j]); when j>i
数组长度为n,首先我们令 i = 0; j = n - 1; 此时 (j - i)有最大值;因为我们要寻找的是水量的最大值,当i或j变化时(i++或j–),(j - i)值必然减小,所以只有min(a[i], a[j])值增大时我们才有可能使C增大,而使min(a[i], a[j])增大只有使其中较小的一个变化才有可能
分情况进行讨论:
- a[i] < a[j] –> i = i+1
- a[i+1] > a[i] : min(a[i+1], a[j]) >= min(a[i], a[j]) ✔
- a[i+1] < a[i] : min(a[i+1], a[j]) < min(a[i], a[j])
- a[i] < a[j] –> j = j - 1
- a[j-1] > a[j] : min(a[i], a[j-1]) == min(a[i], a[j])
- a[j-1] < a[j] : min(a[i], a[j-1]) <= min(a[i], a[j])
var i=0;
var j=n-1;
while(i<j){
var t = (j-i)*(a[i]>a[j]?a[j]:a[i]);
if(t > max){
max = t;
}
if(a[i]>a[j]){
j--;
}else{
i++;
}
}