返回

技术知识百科 | 趣解技术难题:接雨水问题

前端

何谓接雨水问题?

接雨水问题本质上是求解柱状图中能容纳的最大雨水量,柱状图的高度即为各柱子的高度。通过计算相邻柱子之间的面积,我们可以确定能盛装的雨水量。

解决接雨水问题的经典算法

  1. 暴力解法 :使用双层循环遍历柱状图中的每个柱子,并计算每两个柱子之间能盛装的雨水量。时间复杂度为 O(n^2)。

  2. 动态规划 :通过记录前一柱子的高度和最大高度,可以避免重复计算。时间复杂度为 O(n)。

  3. 双指针 :使用两个指针分别指向柱状图的首尾,并在循环中更新指针位置和最大高度。时间复杂度为 O(n)。

以JS实现接雨水问题的解决

// 柱状图高度数组
const heights = [0,1,0,2,1,0,1,3,2,1,2,1];

// 动态规划法解决
const maxAreaDP = (heights) => {
  // 用于记录当前柱子左侧的最大高度
  let leftMax = 0;
  // 用于记录当前柱子右侧的最大高度
  let rightMax = 0;
  // 用于记录总蓄水量
  let maxArea = 0;

  // 双指针
  let left = 0;
  let right = heights.length - 1;

  // 循环遍历柱状图
  while (left < right) {
    // 计算当前柱子左侧的最大高度
    leftMax = Math.max(leftMax, heights[left]);
    // 计算当前柱子右侧的最大高度
    rightMax = Math.max(rightMax, heights[right]);

    // 如果当前柱子左侧的最大高度小于当前柱子右侧的最大高度
    if (leftMax < rightMax) {
      // 当前柱子能盛装的雨水量为当前柱子左侧的最大高度减去当前柱子高度
      maxArea += leftMax - heights[left];
      // 将指针移动到下一个柱子
      left++;
    } else {
      // 当前柱子能盛装的雨水量为当前柱子右侧的最大高度减去当前柱子高度
      maxArea += rightMax - heights[right];
      // 将指针移动到下一个柱子
      right--;
    }
  }

  return maxArea;
};

// 双指针法解决
const maxAreaTwoPointers = (heights) => {
  // 用于记录总蓄水量
  let maxArea = 0;
  // 用于记录当前柱子左侧的最大高度
  let leftMax = 0;
  // 用于记录当前柱子右侧的最大高度
  let rightMax = 0;
  // 双指针
  let left = 0;
  let right = heights.length - 1;

  // 循环遍历柱状图
  while (left < right) {
    // 更新当前柱子左侧的最大高度
    leftMax = Math.max(leftMax, heights[left]);
    // 更新当前柱子右侧的最大高度
    rightMax = Math.max(rightMax, heights[right]);

    // 如果当前柱子左侧的最大高度小于当前柱子右侧的最大高度
    if (leftMax < rightMax) {
      // 当前柱子能盛装的雨水量为当前柱子左侧的最大高度减去当前柱子高度
      maxArea += leftMax - heights[left];
      // 将指针移动到下一个柱子
      left++;
    } else {
      // 当前柱子能盛装的雨水量为当前柱子右侧的最大高度减去当前柱子高度
      maxArea += rightMax - heights[right];
      // 将指针移动到下一个柱子
      right--;
    }
  }

  return maxArea;
};

// 调用并打印结果
console.log(maxAreaDP(heights));
console.log(maxAreaTwoPointers(heights));

希望这篇文章能帮助您理解接雨水问题的解决思路和实现方法。如果您有兴趣了解更多技术知识,请继续关注我们!