leetcode 95 不同的二叉搜索树II

package com.example.lettcode.dailyexercises;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * @Class GenerateTrees
 * @Description 95 不同的二叉搜索树II
 * 给定一个整数 n,生成所有由 1 ... n 为节点所组成的 二叉搜索树 。
 * 示例:
 * 输入:3
 * 输出:
 * [
 *   [1,null,3,2],
 *   [3,2,null,1],
 *   [3,1,null,null,2],
 *   [2,1,3],
 *   [1,null,2,null,3]
 * ]
 * 解释:
 * 以上的输出对应以下 5 种不同结构的二叉搜索树:
 * <p>
 * 1         3     3      2      1
 * \       /     /      / \      \
 * 3     2     1      1   3      2
 * /     /       \                 \
 * 2     1         2                 3
 * <p>
 * 提示:
 * 0 <= n <= 8
 * @Author 
 * @Date 2020/7/15
 **/
public class GenerateTrees {
    static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        TreeNode() {
        }

        TreeNode(int val) {
            this.val = val;
        }

        TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
    }


    public static List<TreeNode> generateTrees(int n) {
        if (n < 1) return new ArrayList<>();
        // dp[i] 表示n=i时所能取得的二叉搜索树
        List<TreeNode>[] dp = new List[n + 1];
        for (int i = 0; i <= n; i++) {
            dp[i] = new ArrayList<>();
        }
        dp[1] = new ArrayList<>(Arrays.asList(new TreeNode(1)));
        for (int i = 2; i <= n; i++) {
            for (int j = 0; j < i; j++) {
                dp[i].addAll(getNodeList(dp, j, i - j - 1));
            }
        }
        return dp[n];
    }

    private static List<TreeNode> getNodeList(List<TreeNode>[] dp, int i, int j) {
        List<TreeNode> res = new ArrayList<>();
        // 左子树不变,右子树加上root.val
        int sizeL = i == 0 ? 1 : dp[i].size(); // 左子树个数
        int sizeR = j == 0 ? 1 : dp[j].size(); // 右子树个数
        int size = sizeL * sizeR; // 左右子树的可能性
        for (int k = 0; k < size; k++) {
            TreeNode root = new TreeNode(i + 1);
            // k/sizeR 表示每次以此选择左子树,然后依次把右子树都遍历一遍
            root.left = i == 0 ? null : dp[i].get(k / sizeR);
            // (k%sizeR) 从0...sizeR-1 + roo.val ,是因为右子树的元素都比根节点大,分别大1,2,3...,sizeR-1
            root.right = j == 0 ? null : copyTree(dp[j].get(k % sizeR), root.val);
            res.add(root);
        }
        return res;
    }

    // 递归是为了右子树的每个元素都加上sizeAdd(也就是根节点的值)
    private static TreeNode copyTree(TreeNode treeNode, int sizeAdd) {
        if (treeNode == null) return null;
        TreeNode node = new TreeNode(treeNode.val + sizeAdd);
        node.left = copyTree(treeNode.left, sizeAdd);
        node.right = copyTree(treeNode.right, sizeAdd);
        return node;
    }

    public static void main(String[] args) {
        int n = 5;
        List<TreeNode> treeNodeList = generateTrees(n);
        System.out.println("GenerateTrees demo01 result:" + treeNodeList.size());
    }
}
posted @ 2020-07-21 15:58  枫叶艾辰  阅读(127)  评论(0)    收藏  举报