代码随想录算法训练营第十八天|513.找树左下角的值、112. 路径总和、113.路径总和ii、 106.从中序与后序遍历序列构造二叉树 、105.从前序与中序遍历序列构造二叉树

513.找树左下角的值

 题目链接/文章讲解/视频讲解:代码随想录

1.代码展示

//513找树左下角的值
    int findResult;
    int findMaxHeight = INT_MIN;
    void findTravelsal(TreeNode* node, int& height) {
        //step1 确定参数
        //step2 确定终止条件
        if (node->left == nullptr && node->right == nullptr) {
            //此时为叶子节点
            if (height > findMaxHeight) {
                //更新最大高度,更新结果
                findMaxHeight = height;
                findResult = node->val;
                return;
            }
            return;
        }
        //step3 确定单层迭代逻辑
        //左子节点
        if (node->left != nullptr) {
            height++;
            findTravelsal(node->left, height);
            //回溯
            height--;
        }
        //右子节点
        if (node->right != nullptr) {
            height++;
            findTravelsal(node->right, height);
            height--;
        }
        //中不需要做逻辑处理
        return;
    }
    int findBottomLeftValue(TreeNode* root) {
        int height = 0;
        findTravelsal(root, height);
        return findResult;
    }

2.本题小节

         主要思路:首先要明确左下角的值是在叶子节点处,同时递归到叶子节点也是终止条件,因此寻找左下角的值是在终止条件中寻找的,同时要注意,只有当前叶子节点的深度大于最大深度时,才能更新结果;其次要注意的是深度,每次递归时需要++,递归结束后需要回溯,高度--;最后要注意的是必须先左后右,只有这样,在同一深度下,才能优先找到左值。

112. 路径总和

 题目链接/文章讲解/视频讲解:代码随想录

1.代码展示

   //112.求总路径和
    bool hasPathSumTravelsal(TreeNode* node, int targetSum) {
        //step1 确定迭代参数
        //step2 确定终止条件
        if (node->left == nullptr && node->right == nullptr && targetSum == 0) {
            //该路径符合条件
            return true;
        }
        if (node->left == nullptr && node->right == nullptr && targetSum != 0) {
            //该路径不符合条件
            return false;
        }
        //step3 确定单层迭代逻辑
        //左
        if (node->left != nullptr) {
            targetSum -= node->left->val;
            bool isPathL = hasPathSumTravelsal(node->left, targetSum);
            targetSum += node->left->val;
            if (isPathL) {
                return true;
            }
        }
        //右
        if (node->right != nullptr) {
            targetSum -= node->right->val;
            bool isPathR = hasPathSumTravelsal(node->right, targetSum);
            targetSum += node->right->val;
            if (isPathR) {
                return true;
            }
        }
        //非叶子节点或者左右两边都不符合
        return false;

    }
    bool hasPathSum(TreeNode* root, int targetSum) {
        if (root != nullptr) {
            return hasPathSumTravelsal(root, targetSum - root->val);
        }
        else {
            return false;
        }
    }

2.本题小节

        主要思路:本题和“求根节点到叶子节点的路径”很像,首先要明确的是本题判断路径总和是在叶子节点中判断的,也就是在终止条件中判断的,有两种情况,一种是targetsum最终递归为0,那么返回为true,如果不为0,返回为false;然后需要注意的是本题也用到了回溯,进行左右子树递归前,先减掉左右子树的val,递归后,再加回来;最后要注意的是,只要找到一条满足路径综合条件的路径,就满足题意了,因此每次左右递归时,会进行判断,满足条件,就直接return true。

113.路径总和ii

1.代码展示

   //113.路径总和Ⅱ
    void pathSumTravelsal(TreeNode* node, int targetSum, vector<int>& vnPath, vector<vector<int>>& vvnTotalPath) {
        //step1 确定参数
        //step2 确定中止条件
        if (node->left == nullptr && node->right == nullptr && targetSum == 0) {
            //叶子节点且为目标路径
            vvnTotalPath.push_back(vnPath);
            return;
        }
        if (node->left == nullptr && node->right == nullptr && targetSum != 0) {
            return;
        }
        //step3 确定单层迭代逻辑
        //左
        if (node->left != nullptr) {
            targetSum -= node->left->val;
            vnPath.push_back(node->left->val);
            pathSumTravelsal(node->left, targetSum, vnPath, vvnTotalPath);
            //回溯
            targetSum += node->left->val;
            vnPath.pop_back();
        }
        //右
        if (node->right != nullptr) {
            targetSum -= node->right->val;
            vnPath.push_back(node->right->val);
            pathSumTravelsal(node->right, targetSum, vnPath, vvnTotalPath);
            //回溯
            targetSum += node->right->val;
            vnPath.pop_back();
        }
        return;

    }
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        vector<vector<int>> vvnTotalPath;
        vector<int> vnPath;
        if (root != nullptr) {
            vnPath.push_back(root->val);
            pathSumTravelsal(root, targetSum - root->val, vnPath, vvnTotalPath);
        }
        return vvnTotalPath;
    }

2.本题小节

        基本思路:这题是上一题的拓展,要把所有满足路径总和的结果都统计出来,就是上一题加上求“根节点到叶子节点的路径”的结合,比上题多了一个vec回溯,用来储存结果,在中止条件中,添加vec,不用在左右迭代处判断,因为这次是要统计所有的情况。

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

题目链接/文章讲解/视频讲解:代码随想录

1.代码展现

    //106.从中序与后序遍历序列构造二叉树
    TreeNode* buildTreeTravelal(vector<int>& inorder, vector<int>& postorder) {
        //step1 确定参数
        //step2 确定中止条件
        //后序为空即初始就为空,则直接返回
        if (postorder.size() == 0) {
            return nullptr;
        }
        //创建父节点
        int rootValue = postorder[postorder.size() - 1];
        TreeNode* node = new TreeNode(rootValue);
        //后序大小为1,则为叶子节点,返回该节点
        if (postorder.size() == 1) {
            return node;
        }
        //step3 确定单层遍历逻辑
        //step3.1 分割中序数组
        //从后序数组中找到父节点
        int index;
        //找到分割点
        for (index = 0; index < inorder.size(); index++) {
            if (rootValue == inorder[index]) {
                break;
            }
        }
        //左中序数组
        vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
        //右中序数组
        //vector<int> rightInorder(inorder.begin() + 1, inorder.end());
        vector<int> rightInorder(inorder.begin() +index + 1, inorder.end());
        //for (int i = 0; i < index + 1; i++) {
        //for (int i = 0; i < index; i++) {
        //    leftInorder.push_back(inorder[i]);
        //}
        //右中序数组
        //for (int i = index + 1; i < inorder.size(); i++) {
        //    rightInorder.push_back(inorder[i]);
        //}
        //step3.2 分割后序数组
        //左后序数组
        vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
        //右后序数组
        vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end() - 1);
        //左后序数组
        //for (int i = 0; i < ind; i++) {
        //    leftPosorder.push_back(postorder[i]);
        //}
        右后序数组
        //for (int i = ind; i < postorder.size() - 1; i++) {
        //    rightPosorder.push_back(postorder[i]);
        //}
        //step3.3 恢复节点左右子节点
        node->left = buildTreeTravelal(leftInorder, leftPostorder);
        node->right = buildTreeTravelal(rightInorder, rightPostorder);
        return node;

    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if (inorder.size() == 0 || postorder.size() == 0) {
            return nullptr;
        }
        return buildTreeTravelal(inorder, postorder);
    }

2.本题小节

        基本思路:本题的首先要搞懂如何从中序和后序遍历数组中恢复二叉树,并把这个过程用递归法展现出来。首先是确定递归函数,中序和后序数组;然后是确定终止条件,一个是当后序数组为空时,那么就递归完毕,直接返回nullptr,另外一种是当后序数组只有一个元素是,也就是叶子节点,直接返回该节点,但是在这之前,要用后序数组的最后一个元素来创建一个节点,作为后面递归的父节点,这个很重要;最后是单层迭代逻辑,也是重头戏,根据后序数组的最后一个元素从中序数组中找到该元素,并记录该元素的index,则开始分割,左边为左前序数组,右边为右前序数组,根据左前序数组的元素个数再从后序元素中分割数组为左后序数组,右后续数组,父节点的左子节点左前序数组和左后序数组进行递归,右子节点用右前序数组和右后序数组递归即可,最后返回父节点。

        思考:不懂画图!!!注意分割方法,容器到容器用迭代器最方便!!!

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

1.代码展现

    //105从中序与后序遍历序列构造二叉树
    TreeNode* buildTreeTravelal(vector<int>& inorder, vector<int>& preorder) {
        //step1 确定参数
        //step2 确定中止条件
        //前序为空即初始就为空,则直接返回
        if (preorder.size() == 0) {
            return nullptr;
        }
        //创建父节点
        int rootValue = preorder[0];
        TreeNode* node = new TreeNode(rootValue);
        //后序大小为1,则为叶子节点,返回该节点
        if (preorder.size() == 1) {
            return node;
        }
        //step3 确定单层遍历逻辑
        //step3.1 分割中序数组
        //从后序数组中找到父节点
        int index;
        //找到分割点
        for (index = 0; index < inorder.size(); index++) {
            if (rootValue == inorder[index]) {
                break;
            }
        }
        //左中序数组
        vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
        //右中序数组
        vector<int> rightInorder(inorder.begin() + index + 1, inorder.end());
        //左前序数组
        vector<int> leftPretorder(preorder.begin() + 1, preorder.begin() + leftInorder.size() + 1);
        //右前序数组
        vector<int> rightPretorder(preorder.begin() + leftInorder.size() + 1, preorder.end());

        //step3.3 恢复节点左右子节点
        node->left = buildTreeTravelal(leftInorder, leftPretorder);
        node->right = buildTreeTravelal(rightInorder, rightPretorder);
        return node;

    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if (inorder.size() == 0 || preorder.size() == 0) {
            return nullptr;
        }
        return buildTreeTravelal(inorder, preorder);
    }

2.本题小节

        基本思路:和上题一样,重点是理解前序中序如何恢复二叉树,对应修改创建的节点,以及分割逻辑即可,不再赘述。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值