返回

利用线段树优化 LeetCode 56:装最多水的容器

前端

引言

LeetCode 56 题「装最多水的容器」要求计算两个垂直线段之间的最大容积,其中线段高度由数组表示,且线段不可倾斜。

传统解法

传统解法采用双指针技术,从数组两端向内移动指针。每一步计算当前指针指向线段之间的容积,更新最大容积。时间复杂度为 O(n)。

线段树优化

线段树是一种分治数据结构,可快速求解区间内最值问题。它将数组划分为多个区间,并对每个区间维护一个数据结构。

线段树工作原理

  • 将数组划分为区间,每个区间包含连续元素。
  • 为每个区间创建一个节点,节点存储区间内元素的最大高度。
  • 节点以树状结构组织,叶子节点对应数组元素,内部节点对应子区间。
  • 对于每个节点,其最大高度等于其子节点的最大高度。

算法优化

利用线段树,我们可以快速求解任意两个线段之间的最小高度。具体步骤如下:

  1. 找到两个线段所在区间,在线段树中查找对应节点。
  2. 求两个节点的最小高度,即两个线段之间的最小高度。
  3. 返回线段长度乘以最小高度,即线段之间的最大容积。

JavaScript 代码

class SegmentTree {
  constructor(nums) {
    this.nums = nums;
    this.n = nums.length;
    this.tree = new Array(4 * n).fill(0);
    this.build(1, 0, n - 1);
  }

  build(node, start, end) {
    if (start === end) {
      this.tree[node] = this.nums[start];
      return;
    }
    const mid = Math.floor((start + end) / 2);
    this.build(2 * node, start, mid);
    this.build(2 * node + 1, mid + 1, end);
    this.tree[node] = Math.max(this.tree[2 * node], this.tree[2 * node + 1]);
  }

  query(node, start, end, l, r) {
    if (l > r) return 0;
    if (start === l && end === r) return this.tree[node];
    const mid = Math.floor((start + end) / 2);
    const left = this.query(2 * node, start, mid, l, Math.min(r, mid));
    const right = this.query(2 * node + 1, mid + 1, end, Math.max(l, mid + 1), r);
    return Math.max(left, right);
  }
}

const maxArea = (nums) => {
  const st = new SegmentTree(nums);
  let max = 0;
  for (let i = 0; i < nums.length - 1; i++) {
    for (let j = i + 1; j < nums.length; j++) {
      const height = st.query(1, 0, nums.length - 1, i, j);
      max = Math.max(max, height * (j - i));
    }
  }
  return max;
};

复杂度分析

线段树优化算法的时间复杂度为 O(n log n),其中 n 是数组长度。相比于传统解法的 O(n^2),线段树优化显著提升了计算效率。

总结

利用线段树优化算法,我们可以高效解决 LeetCode 56 题「装最多水的容器」。线段树的运用展示了数据结构在算法优化中的强大作用。通过深入理解线段树的原理和应用,我们可以解决更复杂的问题,提升算法效率。