声明:小白总结,本意是记录自己的思路,不过希望能帮助别人,那就更好啦,若发现问题,欢迎指正,感谢!!
来源:力扣(LeetCode)
链接:11.盛最多水的容器
题目
给你 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
解析
动态规划
当看到“最多”的时候,想尝试用动态规划解决,取得每个直线与其之前的每个直线组合所能得到的最大值,最后找所有直线的最大值。
// java
class Solution {
public int maxArea(int[] height) {
int n = height.length;
int max = 0;
int[] dp = new int[n];//存放每个直线能得到的最大值
for(int i = 1; i < n; i++){
dp[i] = dpMax(height, i);
//得到其中最大的值即为所求
max = Math.max(dp[i], max);
}
return max;//数组中最大的值
}
private int dpMax(int[] height, int a){
//得到此位置的直线与其之前的每条直线组合的大小
int ans = 0, res = 0;
for(int i = 0; i < a; i++){
res = Math.min(height[i],height[a]) * (a - i);
//记录此直线得到的最大值
ans = Math.max(ans, res);
}
return ans;//此直线能得到的最大值
}
}
双指针
这个题目也可以用双指针解决,在看到官方题解时明白的,记录一下解法。用双指针解决主要是选择两个指针中小的那个去移动的原则
用双指针解决?去移动哪一个指针呢?
怎么能确定移动之后是更大了还是更小了呢?
首先定义两个指针分别指向数组的两端,接下来决定移动哪一个指针:假设当前左右指针分别指向x,y,距离为t,且x < y 。
一、假如移动y,考虑移动后的值y1与y的关系。
①y1>y,那么min(x,y) = x = min(x, y1),其最小值并没有改变,但距离从t变为了t1(t>t1),
②y1<y,若y1<x,则min(x,y1) = y1 <min(x,y) = x,最小值变小了,距离也缩短了;若y1>x,则min(x,y1) = x = min(x,y),最小值没有变但距离缩短了
综上,移动较大值,无论如何所求的值不会超过前一个所求得的
二、假如移动x,如果下一个x1更大了,最小值就会改变,虽然距离也缩小了,但也可以得到更大的盛水量,若下一个x1更小了,就得到了更小的盛水量,但不是一成不变的,而是可以得到更大的盛水量。
即本题的双指针移动原则:移动所指值更小的指针,两指针所指相同时,移动任意一个。
// java
class Solution {
public int maxArea(int[] height) {
int left = 0;//左指针
int right = height.length - 1;//右指针
int ans = 0;
while(left < right){
//得到当前盛水量
int area = Math.min(height[left], height[right]) * (right - left);
//更新最大盛水量
ans = Math.max(ans, area);
//移动较小值的指针
if(height[left] <= height[right]){
left++;
}else{
right--;
}
}
return ans;
}
}
感谢各位巨巨们的帮助,希望在记录分析题目的条件下算法能有所提升……