题意:

image.png

解题思路:

  1. 思路:
  2. 1. 双指针扫描 O(n)
  3. 1.1 找到图中最高的矩形,然后从左至右扫描到最高点,从右到左扫描到最高点;
  4. 1.2 从左至右扫描到最高点,如果右边矩形高度小于左边矩形高度,计算差值;
  5. 1.3 从右到左扫描到最高点,如果左边矩形高度右边右边矩形高度,计算差值;
  6. 1.4 最后统计总差值
  7. 2. (单调栈) O(n)
  8. 1.1 如果要求水的面积,一定要形成一个U字形
  9. 1.2 维护一个递减的单调栈,如果下一个i大于栈顶元素,我们pop出栈顶的元素(即凹槽的部分),再判断是否栈顶元素是否为空,如果不为空,则一定可以形成一个U字形
  10. 1.3 计算U形面经:($i - $stack->top() - 1) * (min($height[$i], $height[$stack->top()]) - $height[$top]);
  11. 1.4 min($height[$i], $height[$stack->top()] : 木桶原理,蓄水的面经由最短的那块板子决定
  12. 1.5 (min($height[$i], $height[$stack->top()]) - $height[$top]):如果$height[$top]有值,必须去掉这部分值,不然面积多算了这部分值;

PHP代码实现:

  1. class Solution {
  2. function trap($height) {
  3. $area = 0;
  4. $maxIdx = $this->getHeight($height);
  5. $leftHeight = $height[0];
  6. for ($i = 0; $i < $maxIdx; $i++) {
  7. //下一个小的话就计算面积
  8. if ($leftHeight < $height[$i]) {
  9. $leftHeight = $height[$i];
  10. } else {
  11. $area += $leftHeight - $height[$i];
  12. }
  13. }
  14. $rightHeight = $height[count($height) - 1];
  15. for ($i = count($height) - 1; $i > $maxIdx; $i--) {
  16. if ($rightHeight < $height[$i]) {
  17. $rightHeight = $height[$i];
  18. } else {
  19. $area += $rightHeight - $height[$i];
  20. }
  21. }
  22. return $area;
  23. }
  24. function getHeight($height) {
  25. $maxV = 0;
  26. $maxIdx = 0;
  27. for ($i = 0; $i < count($height); $i++) {
  28. if ($height[$i] > $maxV) {
  29. $maxV = $height[$i];
  30. $maxIdx = $i;
  31. }
  32. }
  33. return $maxIdx;
  34. }
  35. function trapByStack($height) {
  36. $stack = new SplStack;
  37. $res = 0;
  38. for ($i = 0; $i < count($height); $i++) {
  39. if ($stack->isEmpty() || $height[$i] < $height[$stack->top()]) {
  40. $stack->push($i);
  41. } else {
  42. while (!$stack->isEmpty() && $height[$i] > $height[$stack->top()]) {
  43. $top = $stack->pop();
  44. if (!$stack->isEmpty()) {
  45. $res += ($i - $stack->top() - 1) * (min($height[$i], $height[$stack->top()]) - $height[$top]);
  46. }
  47. }
  48. $stack->push($i);
  49. }
  50. }
  51. return $res;
  52. }
  53. }

GO代码实现:

  1. func trap(height []int) int {
  2. if len(height) == 0 { return 0 }
  3. left, right, res, leftMax, rightMax := 0, len(height)-1, 0, 0, 0
  4. for left < right {
  5. if height[left] <= height[right]{
  6. // 左->右
  7. if height[left] >= leftMax {
  8. leftMax = height[left]
  9. } else {
  10. res += leftMax - height[left]
  11. }
  12. left++
  13. } else {
  14. // 右->左
  15. if height[right] >= rightMax {
  16. rightMax = height[right]
  17. } else {
  18. res += rightMax - height[right]
  19. }
  20. right--
  21. }
  22. }
  23. return res
  24. }