题目

题目来源:力扣(LeetCode)

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

示例 1:
image.png

输入: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]]

思路分析

二叉搜索树的关键性质是:根节点的值大于左子树所有节点的值,小于右子树所有节点的值,且左子树和右子树也同样为二叉搜索树

假设当前序列长度为 n ,当我们枚举的根节点的值为 i ,根据二叉搜索树的性质我们可以知道:左子树的节点值的集合为 [1, i - 1] ,右子树的节点值的集合为 [i + 1, n] 。

例如当 n = 2,生成的二叉搜索树会有两中情况:
情况一,根节点为 1,根据二叉搜索树的性质,则左子树为 null,右子树为 2 ;
情况二,根节点为 2,根据二叉搜索树的性质,则左子树为 1 ,右子树为 null ;

我们可以使用递归来解决这道题。递归的入口即为 generateTrees(1, n),出口为当 start > end 的时候,当前二叉搜索树为空,返回空节点即可。

  1. /**
  2. * Definition for a binary tree node.
  3. * function TreeNode(val, left, right) {
  4. * this.val = (val===undefined ? 0 : val)
  5. * this.left = (left===undefined ? null : left)
  6. * this.right = (right===undefined ? null : right)
  7. * }
  8. */
  9. /**
  10. * @param {number} n
  11. * @return {TreeNode[]}
  12. */
  13. var generateTrees = function(n) {
  14. if (n === 0) return [];
  15. const getBSTnum = (left, right) => {
  16. // 根据二叉搜索树的性质,右子树的节点值一定比左子树的节点值大
  17. // 因此 left > right,则返回 [null]
  18. if (left > right) return [null];
  19. // 当左右子树值相等时,说明这个值就是父节点,这里 return [new TreeNode(left 或者 right)] 都是可以的
  20. if (left === right) return [new TreeNode(left)];
  21. const res = [];
  22. // 枚举可行的根节点
  23. for (let i = left; i <= right; i++) {
  24. // 根据二叉搜索树的性质,左子树的节点值都小于根节点,所以左子树的节点值集合为 [1, i - 1]
  25. // 获得所有可行的左子树集合
  26. const leftBst = getBSTnum(left, i - 1);
  27. // 根据二叉搜索树的性质,右子树的节点值都大于于根节点,所以左子树的节点值集合为 [i + 1, n]
  28. // 获得所有可行的右子树集合
  29. const rightBst = getBSTnum(i + 1, right);
  30. // 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
  31. for (let leftKey of leftBst) {
  32. for (let rightKey of rightBst) { // 这里使用 for...of 循环,即使是 [null] 也可以遍历
  33. let root = new TreeNode(i);
  34. root.left = leftKey;
  35. root.right = rightKey;
  36. res.push(root)
  37. }
  38. }
  39. }
  40. return res;
  41. }
  42. return getBSTnum(1, n);
  43. };