动手刷LeetCode-给节点数找所有二叉树


给出节点数,然后找出所有可能的二叉树形状;

小目标

搞懂递归和动态规划

解题思路

解法一:递归法

我们从序列 1 …n 中取出数字 i,作为当前树的树根。于是,剩余 i - 1 个元素可用于左子树,n - i 个元素用于右子树;
不行,我感觉递归太难理解了;宣布失败

class Solution {
public:
    vector<TreeNode*> generateTrees(int n) { // 直接存的就是 指向结构体类型的节点的指针地址
        // 主要给的是节点数,然后给出所有的可能 二叉树形状
        // 题意是理解了,但是短暂没有思路
        if(n==0){
            return {};
        }
        return solve(1,n);
        
    }

private:
    vector<TreeNode*> solve(int left, int right){
	    if (left > right)
		return { nullptr };
	    vector<TreeNode*>res;
	    for (int i = left; i <= right; i++) {
		    vector<TreeNode*> lef_res = solve(left, i - 1);
		    vector<TreeNode*> rig_res = solve(i + 1, right);
		for (int j = 0; j < lef_res.size(); j++) {
			for (int k = 0; k < rig_res.size(); k++) {
				TreeNode *node = new TreeNode(i);
				node->left = lef_res[j];
				node->right = rig_res[k];
				res.push_back(node);
			}
		}
	}
	return res;
    }

};

解法二:动态规划

95%以上的递归都可以用动态规划来改写;
对树的操作和指针理解很有帮助

lass Solution {
public:
    TreeNode* gen(TreeNode* root,int shift){
        if(root==nullptr) return nullptr;
        TreeNode* back = new TreeNode(root->val + shift);
        back->left = gen(root->left,shift);
        back->right = gen(root->right,shift);
        return back;
    }
    TreeNode* copy(TreeNode* root){
        if(root==nullptr) return nullptr;
        TreeNode* back = new TreeNode(root->val);
        back->left = copy(root->left);
        back->right = copy(root->right);
        return back;
    }
    vector<TreeNode*> generateTrees(int n) {
        vector<vector<TreeNode*>> dp(n+1);
        if(n==0) return dp[0];
        dp[0].push_back(nullptr);
        dp[1].push_back(new TreeNode(1));
        for(int i=2; i<=n ;i++){
            for(int j=1;j<=i;j++){
                TreeNode* temp = new TreeNode(j);
                for(int k=0;k<dp[j-1].size();k++){  //连接左子树
                    temp->left = dp[j-1][k];
                    for(int z=0;z<dp[i-j].size();z++){
                        if(dp[i-j][z])
                           // cout << i-j <<dp[i-j][z]->val << endl;
                        temp->right = gen(dp[i-j][z],j);
                        TreeNode* push = copy(temp); //浅拷贝,若直接压入vector会有问题。
                        dp[i].push_back(push);
                    }               //连接右子树
                }
            }
        }
        return dp[n];
    }
};

注意多使用私有方法

class Solution {
public:
    vector<TreeNode*> generateTrees(int n) {
        vector<TreeNode*> dp;
        if( n == 0 )
            return dp;
        dp.push_back(new TreeNode(1));
        for( int i = 2; i <= n; i++ ) 
        {
            int size =  dp.size();
            for( int j = 0; j < size; j++ )
            {
                TreeNode *head = dp[j];
                TreeNode *p = head;
                while( p != NULL )
                {
                    TreeNode *newHead = copyTree(head);
                    TreeNode *node = search(newHead,p->val);
                    TreeNode  *nodeRight = node->right;
                    TreeNode *insertNode = new TreeNode(i);
                    node->right = insertNode;
                    insertNode->left = nodeRight;
                    dp.push_back(newHead);
                    p = p->right;
                }
                TreeNode *newHead = new TreeNode(i);
                newHead->left = copyTree(head);
                dp[j] = newHead;
            }
        }
        return dp;   
    }
    TreeNode* copyTree( TreeNode *node )
    {
        if( node == NULL)
            return node;
        TreeNode *newNode = new TreeNode(node->val);
        newNode->left = copyTree(node->left);
        newNode->right = copyTree(node->right);
        return newNode;
    }
    TreeNode* search( TreeNode *node, int val )
    {
        if(  node == NULL )
            return node;
        if( node->val > val )
            return search(node->left,val);
        else if( node->val < val  )
            return search(node->right,val);
        else
            return node;
    }
};

** 看代码没有框架思路,看起来很头疼;还有不能只是眼看,还是得用手写出来,画出来**

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值