代码随想录算法训练营第十八天|LeetCode513 找树左下角的值、LeetCode112 路径总和、LeetCode113路径总和II、 LeetCode106、105 从遍历序列构造二叉树

文章介绍了如何利用递归方法解决五个与二叉树相关的问题,包括找树左下角的值、路径总和的判断、路径总和II、中序与后序遍历序列构造二叉树,以及从前序与中序遍历序列构建。重点强调了递归遍历和回溯在解决问题中的应用。
摘要由CSDN通过智能技术生成

513.找树左下角的树

思路:利用递归遍历,后序遍历的顺序(前中后序都可以,因为都是先左后右),当遍历到叶子节点时,记录深度,如果比之前记录的深度更深则更新深度,和最深的叶子节点的值,遍历所有结点后,返回值。

class Solution {
public:
    int result;
    int maxDepth = INT_MIN;
    void getleftnum(TreeNode*root,int depth)
    {
        if(root->left==NULL&&root->right==NULL)//叶子节点就返回
        {
            if(depth>maxDepth)
            {
                maxDepth = depth;
                result = root->val;
            }
            return;
        }
        if(root->left)
        {
            depth++;
            getleftnum(root->left,depth);
            depth--;//回溯
        }
        if(root->right)
        {
            depth++;
            getleftnum(root->right,depth);
            depth--;
        }
        return;
    }
    int findBottomLeftValue(TreeNode* root) {
        getleftnum(root,1);
        return result;


    }
};

112.路径总和

思路:利用递归遍历,当遍历到叶子节点时,判断targetSum值是否为0,如果为0,说明该条路径为满足条件的路径,直接返回true,如果遍历所有节点都没有满足条件的路径,则返回false。每向下遍历时,targetSum减去对应节点的值。 回溯。

class Solution {
public:
    bool traversal(TreeNode* root, int targetSum)
    {
        if(root->left==NULL&&root->right==NULL&&targetSum==0)
        {
            return true;
        }
        if(root->left==NULL&&root->right==NULL&&targetSum!=0)
        {
            return false;
        }
        if(root->left)
        {
            targetSum-=root->left->val;
            if(traversal(root->left,targetSum))
            {
                return true;
            }
            targetSum+=root->left->val;
        }
        if(root->right)
        {
            targetSum-=root->right->val;
            if(traversal(root->right,targetSum))
            {
                return true;
            }
            targetSum+=root->right->val;
        }
        return false;
    }

    bool hasPathSum(TreeNode* root, int targetSum) {
        //递归
        if(root==NULL)
        {
            return false;
        }
        return traversal(root,targetSum-root->val);
    }
};

113.路径总和II

思路:题目要返回满足条件的路径集合,则建立全局变量vector<vector<int>> result,vector<int> path。path用来记录路径节点,result用来存放满足条件的path。利用递归遍历,同上一题,只不过在单层遍历中,向下遍历时向path输入当前节点的值,回溯时也要推出这个值。当遍历到叶子节点时,如果targetSum=0,就把path输入result。遍历所有结点后,返回result。

class Solution {
public:
vector<vector<int>> result;
vector<int> path;
    void traversal(TreeNode*root,int targetSum)
    {
        if(root->left==NULL&&root->right==NULL&&targetSum==0)
        {
            result.push_back(path);
            return;
        }
        if(root->left==NULL&&root->right==NULL&&targetSum!=0)
        {
            return;
        }
        if(root->left)
        {
            path.push_back(root->left->val);
            targetSum-=root->left->val;
            traversal(root->left,targetSum);
            targetSum+=root->left->val;
            path.pop_back();
        }
        if(root->right)
        {
            path.push_back(root->right->val);
            targetSum-=root->right->val;
            traversal(root->right,targetSum);
            targetSum+=root->right->val;
            path.pop_back();
        }
        return;
    }
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        if(root==NULL)
        {
            return result;
        }
        path.push_back(root->val);
        traversal(root,targetSum- root->val);
        return result;
    }
};

106.从中序与后序遍历序列构造二叉树

思路:后序遍历序列的最后一个节点为当前层的根节点,前面的序列分为左树序列和右树序列。利用递归遍历,当中序和后序序列的大小都为0时,说明二叉树构造完毕,返回root。先在后序序列中找到当前层的根节点,然后在中序序列中分割出来中序左树序列和中序右树序列,然后根据左树序列的大小,在后序序列中分割出来后序左树序列和后序右树序列。当前层的根节点的左右子节点分别为下一层递归得到的节点。

class Solution {
public:
    TreeNode* traversal(vector<int>& inorder, vector<int>& postorder) {
//如果后序数组大小为零,说明是空数组
        if(postorder.size()==0)
        {
            return NULL;
        }

        //后序数组最后一个元素为根节点
        int rootvalue = postorder[postorder.size()-1];
        TreeNode* root = new TreeNode(rootvalue);
        
        //如果后序遍历数组大小为1,说明是叶子节点
        if(postorder.size()==1)
        {
            return root;
        }
        //找切割点
        int delimiterIndex;
        for(delimiterIndex=0;delimiterIndex<inorder.size();delimiterIndex++)
        {
            if(inorder[delimiterIndex]==root->val)
            {
                break;
            }
        }
        //切割中序数组,得到中序左数组和中序右数组
        vector<int> midleft;
        vector<int> midright;
        for(int i =0;i<delimiterIndex;i++)
        {
            midleft.push_back(inorder[i]);
        }
        for(int i =delimiterIndex+1;i<inorder.size();i++)
        {
            midright.push_back(inorder[i]);
        }
        //切割后序数组,得到后序左数组和后序右数组
        vector<int> posleft;
        vector<int> posright;
        for(int i = 0;i<midleft.size();i++)
        {
            posleft.push_back(postorder[i]);
        }
        for(int i = midleft.size();i<postorder.size()-1;i++)
        {
            posright.push_back(postorder[i]);
        }
        root->left = traversal(midleft,posleft);
        root->right = traversal(midright,posright); 
        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(inorder.size()==0||postorder.size()==0)
        {
            return NULL;
        }
        return traversal(inorder,postorder);
    }
};

105.从前序与中序遍历序列构造二叉树

思路:与上一题思路相同,只不过这次根节点的判断在前序的第一个元素,因此分割的方式也会有所改变。

class Solution {
public:
    TreeNode* traversal(vector<int>& preorder, vector<int>& inorder)
    {
        if(preorder.size()==0)
        {
            return NULL;
        }
        int rootnum = preorder[0];
        TreeNode *root = new TreeNode(rootnum);
        if(preorder.size()==1)
        {
            return root;
        }
        int index;
        for( index = 0;index<inorder.size();index++)
        {
            if(inorder[index]==rootnum)
            {
                break;
            }
        }
        vector<int> midleft;
        vector<int> midright;
        //中序左数组
        for(int i =0;i<index;i++)
        {
            midleft.push_back(inorder[i]);
        }
        //中序右数组
        for(int i = index+1;i<inorder.size();i++)
        {
            midright.push_back(inorder[i]);
        }
        vector<int> preleft;
        vector<int> preright;
        //先序左数组
        for(int i =0;i<midleft.size();i++)
        {
            preleft.push_back(preorder[i+1]);
        }
        //先序右数组
        for(int i=midleft.size()+1;i<preorder.size();i++)
        {
            preright.push_back(preorder[i]);
        }
        root->left = traversal(preleft,midleft);
        root->right = traversal(preright,midright);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.size()==0||inorder.size()==0)
        {
            return NULL;
        }
        return traversal(preorder,inorder);
    }
};

收获:

逐渐理解回溯。

熟练使用递归。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值