代码随想录Day18 二叉树 part05 513.找树左下角的值● 112. 路径总和 113.路径总和ii● 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树

 513.找树左下角的值

题目链接:513. 找树左下角的值 - 力扣(LeetCode)

文章链接:代码随想录 (programmercarl.com)

视频链接:怎么找二叉树的左下角? 递归中又带回溯了,怎么办?| LeetCode:513.找二叉树左下角的值

 这道题我的第一想法是一直递归到最左边的值,但是有个问题,题目限制了条件,不仅要最左边,还需要最底层。所以我们还需要通过一个int变量depth找到最底层的左边的节点。依旧是递归的想法(其实层序遍历这道题更简单)。

首先,确认递归参数和返回值,除了二叉树的根节点root,还需要一个int参数表示深度

void traversal(TreeNode* root, int depth)

接着,确认递归终止条件,很简单,就是一直递归到叶子节点,然后让depth和此时记录的maxdepth作比较,如果maxdepth<depth.就令maxdepth=depth,result=root->val。

if(root->left==NULL&&root->right==NULL)
            {
                if(depth>maxdepth)
                {
                    maxdepth=depth;
                    result=root->val;
                }
                return;
            }

最后,确认单层递归逻辑。首先这道题最底层最左边的节点,并不一定是“左孩子”。但是左孩子的优先级依旧比右孩子高,所以我们需要先递归左边,再递归右边。

if(root->left)
{
  depth++;
  traversal(root->left,depth);
  depth--;
}
   if(root->right)
{
  depth++;
  traversal(root->right,depth);
  depth--;
     }

总代码如下:

class Solution {
public:
        int maxdepth=INT_MIN;
        int result;
        void traversal(TreeNode* root,int depth)
        {
            if(root->left==NULL&&root->right==NULL)
            {
                if(depth>maxdepth)
                {
                    maxdepth=depth;
                    result=root->val;
                }
                return;
            }
            if(root->left)//左
            {
                depth++;
                traversal(root->left,depth);//向左递归
                depth--;//回溯
            }
            if(root->right)//右
            {
                depth++;
                traversal(root->right,depth);//向右递归
                depth--;//回溯
            }
        }
    int findBottomLeftValue(TreeNode* root) {
        traversal(root,1);
        return result;
    }
};

depth++;

traversal(root->left,depth);

depth--;

这一段代码体现了回溯的过程,我的理解是一层递归结束后,指针就会自动指向它的上一层节点,而depth(深度)不会自己减少,所以需要depth--

这一段代码也可以精简为: traversal(root->left,depth+1) 这样depth本身的值就不会改变。

112. 路径总和

题目链接:112. 路径总和 - 力扣(LeetCode)

文章链接:代码随想录 (programmercarl.com)

视频链接:拿不准的遍历顺序,搞不清的回溯过程,我太难了! | LeetCode:112. 路径总和

 这道题我的第一想法就是通过递归和回溯,将每一个路径的元素之和求出来,放进map里,再从map里查找targetsum,如果有,就return true,否则,return false。方法当然可以做,但是需要构建一个map哈希结构,有些浪费空间,所以,我的第二想法就是每一次递归就减去递归元素,看到叶节点,是否为0.

代码如下:

class Solution {
    public:
     bool traversal(TreeNode* root,int count)    
    {
        if(root->left==NULL&&root->right==NULL&&count==0) return true;//说明有路径,节点元素和刚好为是targetsum
        if(root->left==NULL&&root->right==NULL) return false;
        if(root->left){
            count-=root->left->val;
            if(traversal(root->left,count)) return true;//将true传递
            count+=root->left->val;//回溯
        }
        if(root->right){
            count-=root->right->val;
            if(traversal(root->right,count)) return true;//将true传递
            count+=root->right->val;
        }
        return false;
    }
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root==NULL) return false;//考虑空节点
        return traversal(root,targetSum-root->val);
    }
};
113.路径总和ii

 这道题和上一题的区别在于需要记录符合的路径,所以需要一个一维数组path存放单个路径,一个二维数组result来存放多个路径。

与 昨天所写的 257. 二叉树的所有路径 有相似之处。代码如下:

class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    void traversal(TreeNode* root,int count)
    {
        if(root==NULL) return;
        if(root->left==NULL&&root->right==NULL&&count==0){
            result.push_back(path);
            return;
        }
        if(root->left)
        {
            path.push_back(root->left->val);
            count-=root->left->val;
            traversal(root->left,count);
            path.pop_back();//回溯
            count+=root->left->val;//回溯
        }
        if(root->right)
        {
            path.push_back(root->right->val);
            count-=root->right->val;
            traversal(root->right,count);
            path.pop_back();//回溯
            count+=root->right->val;//回溯
        }
        return;
    }
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        result.clear();
        path.clear();
        if(root==NULL) return result;
        path.push_back(root->val);
        traversal(root,targetSum-root->val);// 把根节点放进路径
        return result;
    }
};

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

 题目链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

文章链接:代码随想录 (programmercarl.com)

视频链接:坑很多!来看看你掉过几次坑 | LeetCode:106.从中序与后序遍历序列构造二叉树_哔哩哔哩_bilibili

 初次通过两个序列构建二叉树,不是很熟练,在这里讲一下关键的思路。

首先我们要通过序列的性质找到切割点,然后将通过切割点将两个序列切割,再用子序列分别进行递归。

而后序列和中序列有什么关系呢?

首先后序列(左右中)的最后一个元素一定是根节点,然后在中序列中找到该元素,该元素的左边及根节点的左孩子,右边及右孩子,而由于“左孩子”“右孩子”也可以作为各自的根节点,继续向下延申,所以递归的思路就出来了。

代码如下:

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);
        if(postorder.size()==1) return root;
        int delimiterindex;//找切割点
        for(delimiterindex=0;delimiterindex<inorder.size();delimiterindex++)
        {
            if(inorder[delimiterindex]==rootvalue) break;
        }
        vector<int> leftinorder(inorder.begin(),inorder.begin()+delimiterindex);
        vector<int> rightinorder(inorder.begin()+delimiterindex+1,inorder.end());
        postorder.resize(postorder.size()-1);
        vector<int> leftpostorder(postorder.begin(), postorder.begin() + leftinorder.size());
        vector<int> rightpostorder(postorder.begin() + leftinorder.size(), postorder.end());
        root->left=traversal(leftinorder,leftpostorder);//子序列进行递归
        root->right=traversal(rightinorder,rightpostorder);//子序列进行递归
        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if (inorder.size() == 0 || postorder.size() == 0) return NULL;
        return traversal(inorder,postorder);
    }
};

从前序与中序遍历序列构造二叉树 其实总体思路也是一样的,需要找到前序和中序之间,元素的关系。

Day18打卡完成,耗时4小时,不同序列构建二叉树花费了大量时间去理解,再接再厉吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值