算法--------数组--------容纳最多的水
给定 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 length = height.length;
if (length == 0) {
return 0;
}else if (length == 1){
return height[0];
}
int max = 0;
for (int i =0, j =length -1; j > i ; ){
int minHeight = Math.min(height[i], height[j]);
max = Math.max(max,minHeight * (j -i));
if (height[i] > height[j]) {
j--;
}else {
i++;
}
}
return max;
}
}
看到网上优化过的之后:
class Solution {
public int maxArea(int[] height) {
int length = height.length;
if (length == 0) {
return 0;
}else if (length == 1){
return height[0];
}
int max = 0;
for (int i =0, j =length -1; j > i ; ){
int start = height[i];
int end = height[j];
int minHeight = Math.min(start, end);
max = Math.max(max,minHeight * (j -i));
// if (start > end) {
// while (height[--j]<end && j> i);
// }else {
// while (height[++i]<end && j> i);
// }
if (start > end) {
do {
j--;
}while (height[j]<end && j> i);
}else {
do {
i++;
}while (height[i]<start && j> i);
}
}
return max;
}
}
下面分析下解题思路:
双索引,左右开弓。第一次遍历的肯定是左右两边的两个数。这时候,比较两个数,放弃比较小的那个数,继续遍历。为什么可以放过最小的那个数呢?
比如说左边的数,比右边的数小,那么对于左边那个数来说,他存在最大的值,就是最右边那个。因为对于左边那个数来说,和其他任何位置的组合,都没有最右边那个数大,所以,对于左边那个小的数,可以不用再遍历。一定是最大的组合。那么,这个数就可以不用遍历了。以此类推。时间复杂度是O(n);
依次类推可以得到每一个数和其他数组合的最大值。然后得出最大值就可以了。
总结:
1.看到别人的算法,总是可以让自己学到点什么。
2.解题思路很重要。思考问题的方式很重要。
解决过程:
刚开始,我做题的时候,同事在旁边,给我说了思路,左右遍历,然后小的数扔掉。当时,我担心的是,这样的话,会不会错失掉最大值?因为有些情况没有遍历,后来,我去尝试推翻同事的解法,后来发现,他是对的。思路就是上面我写的。嗯,我觉得,对任何人说的,都应该质疑,推翻,这会让你印象更深刻。这才有学习的意义。才有意思。
泰山崩于前而色不变的曹新雨,抱歉