Day02 双指针技巧-接雨水、盛水最多的容器
1、盛水最多的容器
-
思路
- 题意分析:盛水容器的体积公式:MIN[height[l],height[r]]
- 双指针:
- 取 height 数组的左右端点 l、r ,计算并保存此时的容积
- 由上述公式,应该移动 结果(高度小的下标移动)对应的 l、r 下标
注:容积的大小由 下标区间(r-l) 和 **最矮高度**决定。移动矮的一方,容积的面积有变大的可能。反之,则容积的面积不会变大。
-
题解
class Solution { public int maxArea(int[] height) { int left = 0, right = height.length - 1; int res = 0; while (left < right) { // [left, right] 之间的矩形面积 int cur_area = Math.min(height[left], height[right]) * (right - left); res = Math.max(res, cur_area); // 双指针技巧,移动较低的一边 if (height[left] < height[right]) { left++; } else { right--; } } return res; } }
2、接雨水
- 思路
- 局部分析,当每个位置i都接到最多的雨水时,每个位置的和即为问题的解
- | - height[i]
- 题解
class Solution { public int trap(int[] height) { int ans = 0; for (int i = 0; i < height.length; i++) { int l_max = 0; int r_max = 0; for (int j = 0; j < i; j++) { l_max = Math.max(l_max, height[j]); } for (int j = height.length - 1; j > i; j--) { r_max = Math.max(r_max, height[j]); } int max = Math.min(r_max, l_max) - height[i]; ans += Math.max(max, 0); } return ans; } } - 局部分析,当每个位置i都接到最多的雨水时,每个位置的和即为问题的解
- 优化
- l_max和r_max每次都需要在循环中遍历,进行优化
- l_max[] r_max[] 数组进行打表,在循环开始前先进行两次循环
class Solution { public int trap(int[] height) { int ans = 0; int len = height.length; //l_max[i]表示i位置左侧的最大值 int[] l_max = new int[len]; //r_max[i]表示i位置右侧的最大值 int[] r_max = new int[len]; l_max[0] = height[0]; l_max[len - 1] = height[len - 1]; for (int i = 1; i < len; i++) { l_max[i] = Math.max(height[i],l_max[i - 1]); } for (int i = len - 2; i >= 0; i--) { r_max[i] = Math.max(height[i],r_max[i + 1]); } for (int i = 1; i < len - 1; i++) { ans += Math.min(r_max[i], l_max[i]) - height[i]; } return ans; } } - 双指针解法-两端同时接水
- 有i,j位置同时接水。此时有iLeftMAX,iRightMAX和jLeftMAX,jRightMAX
- 双指针,i,j分别为左右指针,即i < j
- iLeftMAX<=jLeftMAX jRightMAX<=iRightMAX (单调栈)。实际双指针只有iLeftMAX和jRightMAX。(l_max和r_max)
-
如果 iLeftMAX > jRightMAX (l_max > r_max) 则 jLeftMAX > jRightMAX。j处雨水应该是 jRightMAX - height[j],i处无法推断)
-
如果 jRightMAX > iLeftMAX (r_max > l_max) 则 iRightMAX > iLeftMAX。i处雨水应该是 iLeftMAX - height[i], j处无法推断)
class Solution { public int trap(int[] height) { int ans = 0; int len = height.length; int l_max = 0; int r_max = 0; int l = 0, r= len - 1; while (l <= r){ l_max = Math.max(l_max,height[l]); r_max = Math.max(r_max,height[r]); if (l_max > r_max){ ans += r_max - height[r]; r --; }else { ans += l_max - height[l]; l ++; } } return ans; } }
- l_max和r_max每次都需要在循环中遍历,进行优化