提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目
互联网大厂们在公司养了一大批ACM竞赛的大佬们,吃完饭就是设计考题,然后去考应聘人员,你要做的就是学基础树结构与算法,然后打通任督二脉,以应对波云诡谲的大厂笔试面试题!
你要是不扎实学习数据结构与算法,好好动手手撕代码,锻炼解题能力,你可能会在笔试面试过程中,连题目都看不懂!比如华为,字节啥的,足够让你读不懂题
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/container-with-most-water
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
示例 1:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1]
输出:1
提示:
n == height.length
2 <= n <= 105
0 <= height[i] <= 104
根据短板理论,短板才是水桶水位最高的地方,超过这个短板高度,水漏了
题意其实你应该很好理解
说白了下图
arr=4 8 6 4 6 4 8
依次给你水桶的板高
你需要任选两个板,来组成一个水桶,装水
(1)你可以选择绿色两块板,则水高为4,底边长5-4=1,故水量是41=4
(2)你可以选择粉色两块板,则水高为4,底边长5-3=2,故水量是42=8
(3)你可以选择橘色两块板,则水高为8,底边长6-1=5,故水量是8*5=40
最后取max就行
这就是本题的意思
显然两块板,就需要双指针搞定
L,R一个在左,一个在右,相当于在看每次地边a最大的情况下,咱们去看看哪些板子最高,越高越好,整最大值
(1)当L小时,短板(瓶颈)就是L,R不动(因为R不是瓶颈,而且此时R距离L最远,a底边最大),
结算水量,然后L++,探索L还有更高的板子吗?
(2)与(1)对称的,当R小时,短板(瓶颈)就是R,L不动(因为L不是瓶颈,而且此时R距离L最远,a底边最大),
结算水量,然后R–,探索R还有更高的板子吗?
(3)当L=R时,俩都是瓶颈,而且此时R距离L最远,结算水量,可以任意让L++,R–,探索有没有更高的LR板子?
中途结算水量,全部更新给max,以获取底边a最大情况下,桶组合最大的水量。【这点其实左神根本就没讲清楚,我自己理解才能捋清】
这么搞的话,LR从两头往中间凑,一定在考虑a最大的情况下,两根板子尽可能高的最优解先更新给max了
比如下图
对于0这个高度8
从R=N-1往左走,不断遇到7777 10
对于与L=0的那个板子,跟它组合的水桶中
那么8–10桶是最优解吗?
不是
因为最开始a最长的时候,8–7这个桶已经是最优解了,中途max遇到8–10这个桶是不会更新的。
其实手撕代码就非常容易了
上面三个条件,三进一
沿途收集max水量
注意两个板子之间的空隙就是1单位
//复习:
//根据短板理论,短板才是水桶水位最高的地方,超过这个短板高度,水漏了
public int maxWater(int[] arr){
if (arr == null || arr.length < 2) return 0;//没法组合桶
//L,R一个在左,一个在右,**相当于在看每次地边a最大的情况下**,咱们去看看哪些板子最高,越高越好,整最大值
int L = 0;
int R = arr.length - 1;//边界,此时地板a最大
int max = 0;//水量
while (L < R){//L=R时,a=0,不要
//中途结算水量,全部更新给max,以获取底边a最大情况下,桶组合最大的水量。
int a = R - L;//不算RL位置,中间扣自然就是1单位长度
int height = Math.min(arr[L], arr[R]);
max = Math.max(max, a * height);//结算
//(1)当L小时,短板(瓶颈)就是L,R不动(因为R不是瓶颈,而且此时R距离L最远,a底边最大),
//结算水量,然后L++,探索L还有更高的板子吗?
if (arr[L] < arr[R]) L++;
//(2)与(1)对称的,当R小时,短板(瓶颈)就是R,L不动(因为L不是瓶颈,而且此时R距离L最远,a底边最大),
//结算水量,然后R--,探索R还有更高的板子吗?
else R--;//23俩条件共用了
//(3)当L=R时,俩都是瓶颈,而且此时R距离L最远,结算水量,可以任意让L++,R--,探索有没有更高的LR板子?
}
return max;
}
核心思想就是:
LR从两头往中间凑,一定在考虑a最大的情况下,两根板子尽可能高的最优解先更新给max了
public static void test(){
// int[] arr = {1,2};
int[] arr = {1,8,6,2,5,4,8,3,7};
Solution solution = new Solution();
System.out.println(solution.maxArea3(arr));
System.out.println(solution.maxWater(arr));
}
public static void main(String[] args) {
test();
}
49
49
去LeetCode测试一把:
class Solution {
public int maxArea(int[] height) {
//根据短板理论,短板才是水桶水位最高的地方,超过这个短板高度,水漏了
if (height == null || height.length < 2) return 0;//没法组合桶
//L,R一个在左,一个在右,**相当于在看每次地边a最大的情况下**,咱们去看看哪些板子最高,越高越好,整最大值
int L = 0;
int R = height.length - 1;//边界,此时地板a最大
int max = 0;//水量
while (L < R){//L=R时,a=0,不要
//中途结算水量,全部更新给max,以获取底边a最大情况下,桶组合最大的水量。
int a = R - L;//不算RL位置,中间扣自然就是1单位长度
int h = Math.min(height[L], height[R]);
max = Math.max(max, a * h);//结算
//(1)当L小时,短板(瓶颈)就是L,R不动(因为R不是瓶颈,而且此时R距离L最远,a底边最大),
//结算水量,然后L++,探索L还有更高的板子吗?
if (height[L] < height[R]) L++;
//(2)与(1)对称的,当R小时,短板(瓶颈)就是R,L不动(因为L不是瓶颈,而且此时R距离L最远,a底边最大),
//结算水量,然后R--,探索R还有更高的板子吗?
else R--;//23俩条件共用了
//(3)当L=R时,俩都是瓶颈,而且此时R距离L最远,结算水量,可以任意让L++,R--,探索有没有更高的LR板子?
}
return max;
}
}
还可以吧?
复杂度:
每一次不是L++,就是R–,L=R碰面停止,整体就遍历一次,N个走完max就出结果,o(n)复杂度
每一个位置i去看看后面所有板子的位置j,形成的水桶,哪个好,更新给max
//暴力解
public int maxArea(int[] height) {
//暴力解:o(n^2)
//每个位置i,其他位置j都过一遍
int max = Integer.MIN_VALUE;
for (int i = 0; i < height.length; i++) {//暴力解,可能在测试时直接挂了,超出了时间限制
for (int j = i + 1; j < height.length; j++) {
max = Math.max(max, (j - i) * Math.min(height[i], height[j]));
}
}
return max;
}
每一个位置i的桶,做瓶颈,其他位置j没有我高的不看,去找更远,更高的桶
public int maxArea2(int[] height) {
//优化暴力:o(n^2)
//每个位置i做一次最低的桶沿,遍历真个数组,如果其他j都还没我高,不管了,否则就乘一遍,
int max = Integer.MIN_VALUE;
for (int i = 0; i < height.length; i++) {
for (int j = 0; j < height.length; j++) {
if (j != i && height[j] >= height[i])
max = Math.max(max, Math.abs(j - i) * height[i]);
//跳过大量的低桶--没用还是o(n^2)
}
}
return max;
}
暴力解代码可以不看
主要看上面的最优解
提示:重要经验:
1)LR从两头往中间凑,一定在考虑a最大的情况下,两根板子尽可能高的最优解先更新给max了
2)当L小,让L探索有没有更高的瓶颈,R也类似,总之保证底边a最大的可能性下,去探索更高的瓶颈,这样算出来的水量是最好的
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。