LeetCode 894.All Possible Full Binary Trees(所有可能的满二叉树)

题目描述:

full binary tree is a binary tree where each node has exactly 0 or 2 children.

Return a list of all possible full binary trees with N nodes.  Each element of the answer is the root node of one possible tree.

Each node of each tree in the answer must have node.val = 0.

You may return the final list of trees in any order.

满二叉树是一类二叉树,其中每个结点恰好有 0 或 2 个子结点。

返回包含 N 个结点的所有可能满二叉树的列表。 答案的每个元素都是一个可能树的根结点。

答案中每个树的每个结点必须有 node.val=0

你可以按任何顺序返回树的最终列表。

Example 1:

Input: 7
Output: [[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]]
Explanation:

Note:

  • 1 <= N <= 20

思路:

该题目用到了递归思想。以前一看到递归程序就头疼,看都看不懂,更别说自己写了,经过了大量的题目实践和摸索,最终才有了一丝丝的头绪。下面说说自己关于递归题目的总结。

实现好递归主要抓住以下两点:

1. 递归的终止条件,也就是递归的最后一层,这一点往往不难,但是写错了整个程序就崩了。

2. 递归逻辑,这也是最难的一点,个人在这里卡了好久,经过了大量的失败后总结了一下几条技巧:

 (1)写程序时尽量不要尝试跟踪递归过程!大部分时候只会越想也复杂,直到完全放弃。只有当自己的程序出错需要检查递归逻辑时,才找一两层递归跟踪一下变量。

 (2)实现递归逻辑时,要假设并坚信下一层的递归返回的数据是正确的,拿来直接用,不要再去纠结下一层递归是怎么准备数据的,也不要怀疑数据的可靠性,也就是第(1)条里说的,尽量不要尝试跟踪递归过程,要把重点放在本层递归上。重要的是,如何在本层递归中,利用下层递归准备好的数据,计算出正确结果并返回给上一层递归。只有当本层递归实现好了,递归的边界条件也没有写错,计算机才能保证从最底层往上递推时每一层递归都是正确的。

了解这几点后,我们再通过该题目巩固一下如何使用递归。

题目给出满二叉树的结点个数,要求打印出所有符合要求的满二叉树。我们可以看到,对于每棵满二叉树,它的子树又是一棵满二叉树,所以这个题目可以用到递归。

递归的边界条件是,结点个数为1的满二叉树只有一种情况。

递归逻辑是:我们可以观察到,欲满足题目要求,每一个父亲结点的左子树或者是右子树的结点个数都必须是奇数个。所以,在本层递归中,通过枚举,我们依次将第偶数个元素(这样才能保证该元素的左边和右边都有奇数个元素)当作是父亲结点,然后利用所有由左边元素构成的满二叉树和所有由右边元素构成的满二叉树,组合出所有由当前层元素构成的满二叉树,然后返回给上一层递归。置于左边元素和右边元素分别是怎么组合的,那就是下一层递归的事情了,就不要去想了。

实现(C++):

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<TreeNode*> allPossibleFBT(int N) {
        vector<TreeNode *> result; //result容器用于保存当前层递归计算的所有结果
        if(N==1){ //递归终止条件(最后一层递归)
            TreeNode* root= new TreeNode(0);
            result.push_back(root);
            return result;
        }
        
        for(int i=2; i<N; i+=2) //依次枚举第偶数个结点当作父亲结点
            for(auto &left:allPossibleFBT(i-1)) //依次枚举左边元素构成的满二叉树
                for(auto &right:allPossibleFBT(N-i)){ //依次枚举右边元素构成的满二叉树

                 //所有由左边元素构成的满二叉树和所有由右边元素构成的所有满二叉树已经由下一层递
                 //归准备好,不用怀疑,直接用
                 //通过三层循环组合出当前层元素构成的所有满二叉树的情况,并保存到result容器中

                    TreeNode* root= new TreeNode(0);
                    root->left=left;
                    root->right=right;
                    result.push_back(root);
                }
        
        return result; //将当前层的计算结果返回给上层递归
        
    }
};

猜你喜欢

转载自blog.csdn.net/Shishishi888/article/details/88797943