「前端刷题」95. 不同的二叉搜索树 II

97 阅读1分钟

「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。

题目

链接:leetcode-cn.com/problems/un…

给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。

示例 1:

**输入:**n = 3 输出:[[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]

示例 2:

**输入:**n = 1 输出:[[1]]

提示:

  • 1 <= n <= 8

思路

类似 96. 不同的二叉搜索树:求以 1 ... n 为节点组成的BST有多少种。这道题是让你构建出所有可能的BST

  • 按照 BST 的定义,如果整数 i 作为根节点,则整数 1 ~ i-1 会去构建左子树,i+1 ~ n 会去构建右子树
  • 以 i 为根节点的 BST 种类数 = 左子树 BST 种类数 * 右子树 BST 种类数
  • 所以,不同的 i 之下,左右 BST 子树任意搭配出不同的组合,就构成了不同的 BST

代码

const generateTrees = (n) => {
  if (n == 0) return [];
  const getAllBSTs = (low, high) => {
    if (low > high) return [null];
    if (low == high) return [new TreeNode(low)];
    const res = [];
    for (let i = low; i <= high; i++) {
      const leftBSTs = getAllBSTs(low, i - 1);
      const rightBSTs = getAllBSTs(i + 1, high);
      for (const leftBST of leftBSTs) {
        for (const rightBST of rightBSTs) {
          const root = new TreeNode(i);
          root.left = leftBST;
          root.right = rightBST;
          res.push(root);
        }
      }
    }
    return res;
  };
  return getAllBSTs(1, n);
};

记忆化递归 代码

const generateTrees = (n) => {
  if (n == 0) return [];
  const memo = new Array(n + 1);
  for (let i = 0; i < memo.length; i++) {
    memo[i] = new Array(n + 1);
  }
  const getAllBSTs = (low, high) => {
    if (low > high) return [null];
    if (memo[low][high]) return memo[low][high];
    if (low == high) return [new TreeNode(low)];
    const res = [];
    for (let i = low; i <= high; i++) {
      const leftBSTs = getAllBSTs(low, i - 1);
      const rightBSTs = getAllBSTs(i + 1, high);
      for (const leftBST of leftBSTs) {
        for (const rightBST of rightBSTs) {
          const root = new TreeNode(i);
          root.left = leftBST;
          root.right = rightBST;
          res.push(root);
        }
      }
    }
    return memo[low][high] = res;
  };
  return getAllBSTs(1, n);
};

其他思路,看代码

/**
 * @param {number} n
 * @return {TreeNode[]}
 */
// BST的创建 选择考虑这两种情况
// 左子树和右子树的划分 一层for
// 左子树集合和右子树集合的组合 2层for
var generateTrees = function (n) {
  function buildTree(start, end) {
    let _result = []
    // 指针交错递归终止
    if (start > end) return [null] // 原来如此 
    // i指针滑动,枚举left和right分段的所有可能
    for (let i = start; i <= end; i++) {
      // 左侧和右侧生成树的集合 返回为数组
      let left = buildTree(start, i - 1)
      let right = buildTree(i + 1, end)
      // 循环左右两侧的树集合 分别拼接到新树上,并且存储到结果数组中
      // 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
      for (const leftNode of left) {
        // left为空是这样的[null] 还是可以进来这个循环的 因为有这种场景你要想通 1==>2==>3 都是右子节点的情况
        for (const rightNode of right) {
          let node = new TreeNode(i)
          node.left = leftNode
          node.right = rightNode
          _result.push(node)
        }
      }
    }
    // 返回指定范围生成的树集合
    return _result
  }
  // n 为 0 是返回[]
  if (n === 0) return []
  // 指定最大范围
  return buildTree(1, n)
}