第二十一天 | 513.找树左下角的值 112.路经总和 113.路径总和|| 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树

题目:513.找树左下角的值

自己写出来了!!!!!还是带回溯!!!!!牛!!!!

class Solution {
public:
    int depth = 0;
    int maxdepth = INT_MIN;
    int result;
    int findBottomLeftValue(TreeNode* root) { 
        depth++;                     //每递归一层,深度加1
        if(root->left == NULL && root->right == NULL){
            if(depth > maxdepth){
                maxdepth = depth;
                return root->val;
            }
        }

        if(root->left){
            result = findBottomLeftValue(root->left);
            depth--;             //每返回一层,回溯一次,深度减1
        }
        
        if(root->right){
            result = findBottomLeftValue(root->right);
            depth--;
        }
        return result;           //不管更没更新,都是目前的最左下角的值,直接返回。
    }
};

题目:112.路经总和(需要重做)

整体思路比较简单,代码细节上需要注意

1.累减代替累加

2.终止条件:遇到叶子节点就进行判断是否符合条件

3.与终止条件对应:终止条件判断的是当前节点是否为叶子节点,那么在上一层递归时一定要判断node->left和node->right,才不会出现空指针异常的错误

class Solution {
public:
    bool traversal(TreeNode *cur, int count){
        if(!cur->left && !cur->right && count == 0) return true;
        if(!cur->left && !cur->right) return false;

        if(cur->left) {
            count -= cur->left->val;
            if(traversal(cur->left, count)) return true;
            count += cur->left->val; //回溯,撤销处理结果
        }

        if(cur->right) {
            count -= cur->right->val;
            if(traversal(cur->right, count)) return true;
            count += cur->right->val; //回溯,撤销处理结果
        }
        
        return false;
    }
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root == NULL) return false;
        return traversal(root, targetSum - root->val);
    }
};

题目:113.路径总和||

思路:设置vec记录每一条路径,result来存放满足条件的路径。每一次递归和回溯在vec里体现。

终止条件:遍历到叶子节点且count累减到0,则这条路径满足条件。

                若仅是叶子节点但count不为零,则直接return

单层处理:若不满足终止条件,则进入单层循环。

        前序遍历:若node->left不为空,则累加并将node->val存入路径,进入递归。递归结束后,回溯到初始状态。

class Solution {
public:
    vector<vector<int>> result;
    vector<int> vec;             //设置vec和result为外部变量,函数不需要返回参数
    void traversal(TreeNode *node, int count){           //终止条件的写法要注意
        if(node->left == NULL && node->right == NULL && count == 0) result.push_back(vec);
        if(node->left == NULL && node->right == NULL) return;

        if(node->left){                 //因为要保证递归时不会空指针异常,这里需要判断左子树不为空
            count -= node->left->val;
            vec.push_back(node->left->val);
            traversal(node->left, count);
            vec.pop_back();
            count += node->left->val;
        }

        if(node->right){
            count -= node->right->val;
            vec.push_back(node->right->val);
            traversal(node->right, count);
            vec.pop_back();
            count += node->right->val;
        }
    }
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        if(root == NULL) return result;
        vec.push_back(root->val);
        traversal(root, targetSum - root->val);
        return result;
    }
};

题目:106.从中序与后序遍历序列构造二叉树(有难度,需要重做,反复做)

思路:怎样找中间节点?看后序遍历的数列,最后一个数字就是中间节点的值。

怎样找左子树和右子树?用刚刚找的中间节点的值去切割中序遍历到的数列,就可得到左子树和右子树。

然后在后序遍历的数列进行同样切割,分成左右子树。再分别在左右子树中看最后一个数字,又为中间节点。

这样两个数列反复相互切割,构造出新数列。

步骤:

        1.后序数组为0,空节点。

        2.后序数组最后一个元素为节点元素

        3.寻找终须数组位置作为切割点

        4.切中序数组

        5.切后序数组

        6.递归处理左区间和右区间

返回值:要返回根据中序和后序数组构造完的二叉树的根节点,故类型为TreeNode *。

终止条件:如果后序数组为0,即size等于0,则return NULL。

单层递归逻辑

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;
        }

        //切割中序数组
        //左闭右开区间:[0, delimiterIndex)
        vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
        //[delomiterIndex + 1, end)
        vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end());

        //postorder舍弃末尾元素
        postorder.resize(postorder.size() - 1);

        //切割后序数组
        //依然左闭右开,注意这里使用了左中序数组大小作为切割点
        //[0, leftInorder.size)
        vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
        //[leftInorder.size(), end)
        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);
    }
};

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

类比着上道题打

class Solution {
public:
    TreeNode* traversal(vector<int>& inorder, vector<int>& preorder){
        if(preorder.size() == 0) return NULL;

        int rootValue = preorder[0];
        TreeNode *root = new TreeNode(rootValue);

        if(preorder.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());

        //切割前
        vector<int> leftPreorder(preorder.begin() + 1, preorder.begin() + 1 + leftInorder.size());
        vector<int> rightPreorder(preorder.begin() + 1 + leftInorder.size(), preorder.end());

        root->left = traversal(leftInorder, leftPreorder);
        root->right = traversal(rightInorder, rightPreorder);

        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(inorder.size() == 0 || preorder.size() == 0) return NULL;
        //左闭右开原则
        return traversal(inorder, preorder);
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值