image.png

BST性质

  • left < root < right
  • 中序遍历是非递减序列

    思路

  • 这题是一个求方案数的题目, 一般想到回溯

  • 难点在于左右子树的处理, 由于给定的是中序(), 实际上任意选择一个root, 都有对应的BST存在。
  1. function generateTrees(n: number): Array<TreeNode | null> {
  2. /* [start, end] */
  3. function dfs(start: number, end: number): Array<TreeNode | null> {
  4. // base case
  5. // 必须啊要null
  6. if (start > end) return [null];
  7. let trees: Array<TreeNode | null> = [];
  8. // make choices
  9. /* 选根节点, 没有产生对同级choice产生影响, 因此不用撤销*/
  10. for (let i = start; i <= end; i++) {
  11. let leftSet = dfs(start, i - 1);
  12. let rightSet = dfs(i + 1, end);
  13. // left
  14. for (let left of leftSet) {
  15. for (let right of rightSet) {
  16. let root = new TreeNode(i);
  17. root.left = left;
  18. root.right = right;
  19. trees.push(root);
  20. }
  21. }
  22. }
  23. return trees;
  24. }
  25. return dfs(1, n);
  26. }
  1. namespace l96_1 {
  2. function numTrees(n: number): number {
  3. /* [start, end] */
  4. const memo: number[][] = new Array(n)
  5. .fill(0)
  6. .map(() => new Array(n).fill(-1));
  7. function dfs(start: number, end: number): number {
  8. // base case
  9. if (start > end) return 1;
  10. let trees: number = 0;
  11. // make choices
  12. /* 选根节点, 没有产生对同级choice产生影响, 因此不用撤销*/
  13. if (memo[start][end] !== -1) return memo[start][end];
  14. for (let i = start; i <= end; i++) {
  15. let leftSet = dfs(start, i - 1);
  16. let rightSet = dfs(i + 1, end);
  17. trees += leftSet * rightSet;
  18. // lef
  19. }
  20. memo[start][end] = trees;
  21. return trees;
  22. }
  23. dfs(0, n - 1);
  24. console.table(memo);
  25. return memo[0][n - 1];
  26. }
  27. console.log(numTrees(5));
  28. }
  29. namespace l96_2 {
  30. function numTrees(n: number): number {
  31. /*
  32. * state: dp[i][j] 表示区间[i, j]BST的方案
  33. * base case: dp[i][j]=1 , i===j
  34. * choice: dp[i][j] = SUM(f(i, j, k));f(i, j, k)表示, root = k 时的方案 , i <= k <= j
  35. */
  36. const dp: number[][] = new Array(n)
  37. .fill(0)
  38. .map((item) => new Array(n).fill(0));
  39. for (let i = 0; i < n; i++) dp[i][i] = 1;
  40. for (let start = 1; start < n; start++) {
  41. for (let i = 0, j = start; j < n; i++, j++) {
  42. // 中心点枚举
  43. for (let k = i; k <= j; k++) {
  44. dp[i][j] +=
  45. (k !== i ? dp[i][k - 1] : 1) *
  46. (k !== j ? dp[k + 1][j] : 1);
  47. }
  48. }
  49. }
  50. console.table(dp);
  51. // base case
  52. return dp[0][n - 1];
  53. }
  54. console.log(numTrees(5));
  55. /* [start, end] */
  56. }
  57. namespace l96_3 {
  58. function numTrees(n: number): number {
  59. /*
  60. * state: 长度为n的序列有dp[n]种方案
  61. * base case: dp[0] = 0 dp[1] = 1
  62. * dp[i] = sum(f(k, i)) 1<=k<=i, f(k, i)为,以k为中心点, 长度为i的bst方案数
  63. * f(k, i) = dp[k-1]*dp[i - k]
  64. */
  65. const G = new Array(n + 1).fill(0);
  66. G[0] = 1;
  67. G[1] = 1;
  68. for (let i = 2; i <= n; ++i) {
  69. /* 枚举中心点 */
  70. for (let j = 1; j <= i; ++j) {
  71. G[i] += G[j - 1] * G[i - j];
  72. }
  73. }
  74. return G[n];
  75. }
  76. /* [start, end] */
  77. }
  • 区间长度相同, BST方案是一样的, 这也是个可以优化的地方
  • 95. 不同的二叉搜索树 II - 图2