动态规划 | 分治法 -- 所有可能的真二叉树

这篇具有很好参考价值的文章主要介绍了动态规划 | 分治法 -- 所有可能的真二叉树。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目描述

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

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

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

示例 1:

动态规划 | 分治法 -- 所有可能的真二叉树,算法题,动态规划,算法,leetcode,java 

输入: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 <= n <= 20

1.  分治

1.1 算法与思路

根据题意可知,真二叉树中的每个结点的子结点数是 0 或 2,此时可以推出真二叉树中的结点数 n 为奇数,可以使用数学归纳法证明:

当真二叉树中只有 1 个结点时,此时 1 为奇数,树中唯一的结点是根结点,。

当真二叉树中有 n 个结点时,根据真二叉树的定义,此时可将其中一个叶结点增加两个子结点之后仍为真二叉树,新的真二叉树中有 n+2 个结点,由于 n 是奇数,此时 n+2 也是奇数。

由于真二叉树中的结点数一定是奇数,因此当给定的节点数 n 是偶数时,此时无法构成真二叉树,返回空值即可。当真二叉树节点数目 n 大于 1 时,此时真二叉树的左子树与右子树也一定为真二叉树,则此时左子树的节点数目与右子树的节点数目也一定为奇数。

当 n 是奇数时,n 个结点的真二叉树满足左子树和右子树的结点数都是奇数,此时左子树和右子树的结点数之和是 n−1,假设左子树的数目为 i,则左子树的节点数目则为 n−1−i,则可以推出左子树与右子树的节点数目序列为:

 

假设我们分别构节点数目为 i 和节点数目为 n−1−i 的真二叉树,即可构造出 n 个结点的真二叉树。我们可以利用分治来构造真二叉树,分治的终止条件是 n=1。

  • 当 n=1 时,此时只有一个结点的二叉树是真二叉树;
  • 当 n>1 时,分别枚举左子树和右子树的根结点数,然后递归地构造左子树和右子树,并返回左子树与右子树的根节点列表。确定左子树与右子树的根节点列表后,分别枚举不同的左子树的根节点与右子树的根节点,从而可以构造出真二叉树的根节点。

1.2 代码

public List<TreeNode> allPossibleFBT(int n) {
        List<TreeNode> fullBinaryTrees = new ArrayList<TreeNode>();
        if (n % 2 == 0) {
            return fullBinaryTrees;
        }
        if (n == 1) {
            fullBinaryTrees.add(new TreeNode(0));
            return fullBinaryTrees;
        }
        for (int i = 1; i < n; i += 2) {
            List<TreeNode> leftSubtrees = allPossibleFBT(i);
            List<TreeNode> rightSubtrees = allPossibleFBT(n - 1 - i);
            for (TreeNode leftSubtree : leftSubtrees) {
                for (TreeNode rightSubtree : rightSubtrees) {
                    TreeNode root = new TreeNode(0, leftSubtree, rightSubtree);
                    fullBinaryTrees.add(root);
                }
            }
        }
        return fullBinaryTrees;
    }

2. 动态规划

2.1 算法与思路

上述同样的解题思路,我们还可以使用自底向上的动态规划。我们可以先构造节点数量为 1 的子树,然后构造节点数量为 5 的子树,然后依次累加即可构造出含有节点数目为 n 的真二叉树。

  • 节点数目序列分别为 [(1,1)] 的子树可以构造出节点数目 3 的子树;
  • 节点数目序列分别为 [(1,3),(3,1)] 的子树可以构造出节点数目 5 的真二叉树;
  • 节点数目序列分别为 [(1,5),(3,3),(5,1)] 的子树可以构造出节点数目 7 的真二叉树;
  • 节点数目序列分别为 [(1,i−2),(3,i−4),⋯ ,(i−2,1)] 的子树可以构造出节点数目 i 的真二叉树;

如果构造节点数目为 n 真二叉树,此时可以从节点数目序列为 [(1,n−2),(3,n−5),⋯ ,(n−2,1)] 的真二叉树中构成,按照所有可能的组合数进行枚举,即可构造成节点数目为 n 的真二叉树。

2.2 代码

public List<TreeNode> allPossibleFBT(int n) {
        List<TreeNode> fullBinaryTrees = new ArrayList<TreeNode>();
        if (n % 2 == 0) {
            return fullBinaryTrees;
        }
        if (n == 1) {
            fullBinaryTrees.add(new TreeNode(0));
            return fullBinaryTrees;
        }
        for (int i = 1; i < n; i += 2) {
            List<TreeNode> leftSubtrees = allPossibleFBT(i);
            List<TreeNode> rightSubtrees = allPossibleFBT(n - 1 - i);
            for (TreeNode leftSubtree : leftSubtrees) {
                for (TreeNode rightSubtree : rightSubtrees) {
                    TreeNode root = new TreeNode(0, leftSubtree, rightSubtree);
                    fullBinaryTrees.add(root);
                }
            }
        }
        return fullBinaryTrees;
    }

3. 参考题目

. - 力扣(LeetCode)文章来源地址https://www.toymoban.com/news/detail-853543.html

到了这里,关于动态规划 | 分治法 -- 所有可能的真二叉树的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【算法心得】硬币通过二叉树传递的题,分治精髓是干自己的事

    https://leetcode.cn/problems/distribute-coins-in-binary-tree/ 这个题刚开始的思路是对树进行一个中序遍历,像有一个铲子从左往右推,所过之处摞起来的金币堆都被铲平,多出来的金币落到右边的金币坑里(或左边的金币坑) 但是这样有一个问题,怎么知道多余的金币是从哪个位置来的

    2024年02月16日
    浏览(35)
  • 四大算法:贪心、分治、回溯、动态规划

    贪心算法(又称贪婪算法),在求解问题时,总是做出在当前看来是最好的选择。也就是说,不从整体最优解进行考虑,而是得到某种意义上的局部最优解。 贪心算法采用自顶向下,以迭代的方法做出贪心选择,每做一次贪心选择,就将所求问题简化为一个规模更小的问题。

    2024年02月15日
    浏览(65)
  • 算法分析与设计---分治+动态规划

    1.分治法 适用条件: 问题规模缩小到一定程度容易求解 问题可以分解为若干个规模较小的 相同 子问题,即问题具有最优子结构( 使用分治法前提 ) 可以利用子问题的解合并为该问题的解( 决定是否使用分治法 ) 各个子问题 相互独立 ,即子问题之间不包含公共子问题(

    2024年02月07日
    浏览(45)
  • 探索经典算法:贪心、分治、动态规划等

    贪心算法是一种常见的算法范式,通常在解决最优化问题中使用。 贪心算法是一种在每一步选择中都采取当前状态下最优决策的算法范式。其核心思想是选择每一步的最佳解决方案,以期望达到最终的全局最优解。这种算法特点在于只考虑局部最优解,而不会回溯或重新考虑

    2024年02月05日
    浏览(44)
  • 求最大字段和(穷举法、动态规划、分治法)

    1、案例要求 给定由n个整数(可能为负整数)组成的序列a1,a2,…,an,求该序列形如: 的子段和的最大值。当所有整数均为负数时定义其最大子段和为0。 分别采用穷举法、分治法、动态规划法完成。 2、算法设计与实现 2.1 穷举法 2.1.1 算法设计思路 通过定义遍历子段起始位置

    2024年02月02日
    浏览(56)
  • LeeCode——回溯法、动态规划、贪心法、分治法(快速说明)

    算法方法 用处 优点 缺点 拓展与改良 回溯法 适用于求解组合问题、排列问题、搜索问题等。 1. 可以搜索整个解空间,找到最优解。 2. 不需要预先知道问题的解可能在哪里。 1. 时间复杂度高,因为需要遍历整个解空间。 2. 需要较大的空间存储搜索轨迹。 1. 剪枝优化。 2. 双

    2024年02月10日
    浏览(86)
  • 力扣 53. 最大子数组和(C语言+分治递归、动态规划)

            给你一个整数数组  nums  ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组  是数组中的一个连续部分。         示例 1:         示例 2:         示例 3: (1)分治递归         分治法的核心部分。

    2024年02月07日
    浏览(37)
  • 【数据结构】二叉树的销毁 & 二叉树系列所有源代码(终章)

    目录 一,二叉树的销毁  二,二叉树系列所有源代码 BTee.h BTee.c Queue.h Queue.c 二叉树建好了,利用完了,也该把申请的动态内存空间给释放了,那要如何释放呢? 我们还是以这棵树为例, 要把这棵树销毁掉,其实就是把树上的结点全部释放掉 ,但是呢这个 释放的顺序挺讲究

    2024年02月08日
    浏览(47)
  • 五大常用算法——分治法,动态规划,回溯法,分支界限法,贪心算法

    (1) 分治法 将一个难以直接解决的大问题,分割成一些规模较小的相同问题 快速排序 快排也是分治的一个实例,快排每一趟会选定一个数,将比这个数小的放左面,比这个数大的放右面, 然后递归分治求解两个子区间,当然快排因为在分的时候就做了很多工作, 当全部分到

    2024年02月04日
    浏览(42)
  • 【leetcode刷题之路】剑指Offer(4)——分治+排序算法+动态规划

    8 分治算法 8.1 【递归】剑指 Offer 07 - 重建二叉树 https://leetcode.cn/problems/zhong-jian-er-cha-shu-lcof/   前序遍历是根左右,中序遍历是左根右,这也就意味着前序遍历的第一个节点是整棵树的根节点,顺着这个节点找到它在中序遍历中的位置,即为in_root,那么in_root左边的都在左子

    2024年02月11日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包