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

513.找树左下角的值
解法一:前序遍历

点击查看代码
class Solution {
public:
    int maxDepth = 0;
    int result;
    void preOrder(TreeNode *root, int depth) {
        if(root == nullptr) return;
        if(depth > maxDepth) {
            maxDepth = depth;
            result = root->val;
        }
        preOrder(root->left, depth + 1);
        preOrder(root->right, depth + 1);
    }
    int findBottomLeftValue(TreeNode* root) {
        preOrder(root, 1);
        return result;
    }
};

无论前、中、后序,只要是先访问左子树后访问右子树的顺序,则在每一层中,必然是该层最左边的节点最先被处理,本题利用该点,使用前序遍历,当depth比maxdepth大时,说明该层第一次被访问处理,当前访问处理的就是该层最左边的节点,将其同步到result中,result会随着depth的增加而不断更新,最终维护的是depth最大(也即最底层)的一层的最左边的节点值

解法二:本题使用层序遍历亦非常合适

点击查看代码
class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        int result;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()) {
            int size = que.size(); //核心语句,记录每层的节点个数
            result = que.front()->val;
            while(size-- > 0) {
                TreeNode *cur = que.front();
                que.pop();
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }
        }
        return result;
    }
};

112.路径总和

点击查看代码
class Solution {
public:
    bool is_exist = 0;
    void preOrder(TreeNode *root, int pathSum, int &targetSum) {
        //if(root == nullptr) return;
        if(root->left == nullptr && root->right == nullptr) {
            if(pathSum == targetSum) is_exist = 1;
        }
        if(root->left) {
            preOrder(root->left, pathSum + root->left->val, targetSum);
        }
        if(root->right) {
            preOrder(root->right, pathSum + root->right->val, targetSum);
        }
    }
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root) {
            preOrder(root, root->val, targetSum);
        }
        return is_exist;
    }
};

本题思想与257.二叉树的所有路径的思想、做法基本一致,将根节点到子节点的路径总和通过参数传递逐层往下传,每层函数、每个节点维护各自到根节点的路经总和

113.路径总和Ⅱ

点击查看代码
class Solution {
public:
    vector<vector<int>> result;
    vector<int> addVal(vector<int> path, int num) { //往vector<int>容器里追加int型数据并返回拷贝值
        path.push_back(num);
        return path;
    }
    void preOrder(TreeNode *root, vector<int> path, int pathSum, int &targetSum) {
        //if(root == nullptr) return;
        if(root->left == nullptr && root->right == nullptr) {
            if(pathSum == targetSum) result.push_back(path);
        }
        if(root->left) {
            preOrder(root->left, addVal(path, root->left->val), pathSum + root->left->val, targetSum);
        }
        if(root->right) {
            preOrder(root->right, addVal(path, root->right->val), pathSum + root->right->val, targetSum);
        }
    }
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        if(root) {
            vector<int> v;
            v.push_back(root->val);
            preOrder(root, v, root->val, targetSum);
        }
        return result;
    }
};

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

点击查看代码
class Solution {
public:
    //区间均采用左闭右开区间,寻找子树的根节点,并将根节点与其左右子树连起来,最后返回该子树
    TreeNode *searchRoot(vector<int> &inorder, int inLeft, int inRight, vector<int> &postorder, int postLeft, int postRight) {
         //步骤一:从后序序列中找该子树的根节点
        if(postLeft == postRight) return nullptr; //空树的根为nullptr

        int rootVal = postorder[postRight - 1];
        TreeNode *root = new TreeNode(rootVal);

        if(postRight - postLeft == 1) return root; //叶子节点直接返回,无需连左右子树

        //步骤二:用此根节点对中序序列划分为 左 根 右
        int indivpoint;
        for(indivpoint = inLeft; indivpoint < inRight; ++indivpoint) {
            if(inorder[indivpoint] == rootVal) break;
        }
        int inleftBegin = inLeft, inleftEnd = indivpoint;
        int inrightBegin = indivpoint + 1, inrightEnd = inRight;

        //步骤三:对后序序列划分为 左 右 根
        int postleftBegin = postLeft, postleftEnd = postLeft + (inleftEnd - inleftBegin);
        //此处-1是去除了最后一个元素,因为其已经作为根节点
        int postrightBegin = postleftEnd, postrightEnd = postRight - 1;

        //步骤四:通过左子树的中序和后序序列找当前根节点的左子树的根节点,并让根节点和它的左子树连起来
        root->left = searchRoot(inorder, inleftBegin, inleftEnd, postorder, postleftBegin, postleftEnd);

        //步骤五:通过右子树的中序和后序序列找当前根节点的右子树的根节点,并让根节点和它的右子树连起来
        root->right = searchRoot(inorder, inrightBegin, inrightEnd, postorder, postrightBegin, postrightEnd);

        //步骤五:返回找到的本子树的根节点
        return root;

    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        return searchRoot(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    }
};

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

点击查看代码
class Solution {
public:
    //区间均采用左闭右开区间,寻找子树的根节点,并将根节点与其左右子树连起来,最后返回该子树
    TreeNode *searchRoot(vector<int> &preorder, int preLeft, int preRight, vector<int> &inorder, int inLeft, int inRight) {
         //步骤一:从前序序列中找该子树的根节点
        if(preLeft == preRight) return nullptr; //空树的根为nullptr

        int rootVal = preorder[preLeft];
        TreeNode *root = new TreeNode(rootVal);

        if(preRight - preLeft == 1) return root; //叶子节点直接返回,无需连左右子树

        //步骤二:用此根节点对中序序列划分为 左 根 右
        int indivpoint;
        for(indivpoint = inLeft; indivpoint < inRight; ++indivpoint) {
            if(inorder[indivpoint] == rootVal) break;
        }
        int inleftBegin = inLeft, inleftEnd = indivpoint;
        int inrightBegin = indivpoint + 1, inrightEnd = inRight;

        //步骤三:对前序序列划分为 根 左 右 ,此处+1是去除了第一个元素,因为其已经作为根节点
        int preleftBegin = preLeft + 1, preleftEnd = preLeft + 1 + (inleftEnd - inleftBegin);
        int prerightBegin = preleftEnd, prerightEnd = preRight;

        //步骤四:通过左子树的前序和中序序列找当前根节点的左子树的根节点,并让根节点和它的左子树连起来
        root->left = searchRoot(preorder, preleftBegin, preleftEnd, inorder, inleftBegin, inleftEnd);

        //步骤五:通过右子树的前序和中序序列找当前根节点的右子树的根节点,并让根节点和它的右子树连起来
        root->right = searchRoot(preorder, prerightBegin, prerightEnd, inorder, inrightBegin, inrightEnd);

        //步骤五:返回找到的本子树的根节点
        return root;

    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return searchRoot(preorder, 0, preorder.size(), inorder, 0, inorder.size());
    }
};

执行过程:根节点是从上往下找的,树的连接是从下往上连的,即下层连接完成后,再连往上层,最终整体连接完毕,返回整棵树的根节点

2025/02/28

posted @ 2025-02-28 16:50  coder小杰  阅读(15)  评论(0)    收藏  举报