从零学算法894

894 .给你一个整数 n ,请你找出所有可能含 n 个节点的 真二叉树 ,并以列表形式返回。答案中每棵树的每个节点都必须符合 Node.val == 0 。

答案的每个元素都是一棵真二叉树的根节点。你可以按 任意顺序 返回最终的真二叉树列表。

真二叉树 是一类二叉树,树中每个节点恰好有 0 或 2 个子节点。

示例 1:

输入:n = 7

输出:[[0,0,0,null,null,0,0,null,null,0,0],[0,0,0,null,null,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,null,null,null,null,0,0],[0,0,0,0,0,null,null,0,0]]

示例 2:

输入:n = 3

输出:[[0,0,0]]

  • 分治:从根节点开始构建真二叉树时,初始节点数为 1,由于真二叉树的每个节点只会有 0 或 2 个子节点,所以构建一次后,节点总数只会为 1+0 或者 1+2,同理继续构建下去,增加的节点数必定为 2 的倍数,所以要构建真二叉树,首先节点总数 n 一定为奇数。同理左右子树的节点数也一定为奇数,所以假设左子树有 i 个节点,那么右子树就包含 n-i-1 个节点,并且可以推出左右节点数的组合序列为 [(1,n-2),(3,n-4),...,(n-2,1)]。此时可以利用分治法分构建真二叉树,终止条件为当 n = 1,返回只有一个根节点的真二叉树,当 n > 1 时我们枚举左右子树节点数的可能性并组合所有可能性即可
java 复制代码
  public List<TreeNode> allPossibleFBT(int n) {
      List<TreeNode> ans = new ArrayList<>();
      if(n % 2==0)return ans;
      if(n == 1){
          ans.add(new TreeNode(0));
          return ans;
      }
      for(int i=1;i<n;i+=2){
      	  // 返回当节点数为 i 时左子树所有可能的结构
      	  // 比如示例 1,当 i = 1 时就表示左子树只有一个节点
          List<TreeNode> left = allPossibleFBT(i);
          // 返回当节点数为 n-i-1 时右子树所有可能的结构
          // 比如当 i 为 1 时表示右子树共有 5 个节点
          // 共有 5 个节点的真二叉树只有两种可能
          // 最后组合成了图中前面两种可能
          List<TreeNode> right = allPossibleFBT(n - 1 - i);
          // 两两组合加入结果列表
          for(TreeNode l:left){
              for(TreeNode r:right){
                  TreeNode root = new TreeNode(0, l,r);
                  ans.add(root);
              }
          }
      }
      return ans;
  }
  • 动态规划:还是上述的思路,同样可以用动态规划的方式去解。假设 dp[i] 为节点总数为 i 时的所有真二叉树,我们从 dp[1] 开始构造,dp[1] 表示只有根节点没有左右子树,左右子树节点数的可能的组合为 [],构建 dp[3] 的左右子树节点数可能的组合为 [(1,1)](表示左子树为 dp[1],右子树为 dp[1]),构建 dp[5] 的组合为 [(1,3),(3,1)],dp[7] 的组合为 [(1,5),[3,3],[5,2]],dp[n] 的组合为 [(1,n-2),(3,n-4),...,(n-2,1)],还是同理遍历这些可能组在一起即可
  • 比如 dp[7] 可以由左子树为 dp[1],右子树为 dp[5] 的所有可能组合而成得到示例 1 结果图中前两种结果,也能由左右子树都为 dp[3] 的可能组合而成得到图中第三种结果,还能由左子树为 dp[5],右子树为 dp[1] 的所有可能组合而成得到图中最后两种结果
java 复制代码
  public List<TreeNode> allPossibleFBT(int n) {
      if(n % 2==0)return new ArrayList<TreeNode>();
      List<TreeNode>[] dp = new List[n+1];
      // 初始化为空列表
      for (int i = 0; i <= n; i++) {
          dp[i] = new ArrayList<TreeNode>();
      }
      // 赋值节点总数为 1 的初始值 dp[1]
      dp[1].add(new TreeNode(0));
      // 获取节点总数为 3,5,7.. 的真二叉树列表
      for(int i=3;i<=n;i+=2){
          // 从左子树节点总数为 1 开始枚举左右子树的可能
          for(int j=1;j<i;j+=2){
              // 老样子,组合左右子树得到所有可能
              for(TreeNode left:dp[j]){
                  for(TreeNode right:dp[i-1-j]){
                      TreeNode root = new TreeNode(0, left, right);
                      dp[i].add(root);
                  }
              }
          }
      }
      return dp[n];
  }
相关推荐
hsling松子4 小时前
使用PaddleHub智能生成,献上浓情国庆福
人工智能·算法·机器学习·语言模型·paddlepaddle
dengqingrui1235 小时前
【树形DP】AT_dp_p Independent Set 题解
c++·学习·算法·深度优先·图论·dp
C++忠实粉丝5 小时前
前缀和(8)_矩阵区域和
数据结构·c++·线性代数·算法·矩阵
ZZZ_O^O5 小时前
二分查找算法——寻找旋转排序数组中的最小值&点名
数据结构·c++·学习·算法·二叉树
CV-King6 小时前
opencv实战项目(三十):使用傅里叶变换进行图像边缘检测
人工智能·opencv·算法·计算机视觉
代码雕刻家6 小时前
数据结构-3.9.栈在递归中的应用
c语言·数据结构·算法
雨中rain6 小时前
算法 | 位运算(哈希思想)
算法
Kalika0-08 小时前
猴子吃桃-C语言
c语言·开发语言·数据结构·算法
sp_fyf_20248 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-02
人工智能·神经网络·算法·计算机视觉·语言模型·自然语言处理·数据挖掘
我是哈哈hh10 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝