第六章 二叉树part04

2026.03.13 02.12 第十六天

513 找树左下角的值

左下角的值是最深一层,从左到右第一个叶子节点的值。

递归法:

遍历到每个节点都判断当前深度,每一次出现更深的节点就可能是左下角的节点,最后一次出现的更深的节点就是要找的节点。

class Solution {
public:
    int maxDepth = INT_MIN;
    int result;

    void travelsal(TreeNode* node, int depth) {
        if(node->left == nullptr && node->right == nullptr) {
            if(depth > maxDepth) {
                maxDepth = depth;
                result = node->val;
            }
        }
        if(node->left) {
            depth++;
            travelsal(node->left, depth);
            depth--;
        }
        if(node->right) {
            depth++;
            travelsal(node->right, depth);
            depth--;
        }
        return;
    }

    int findBottomLeftValue(TreeNode* root) {
        travelsal(root, 0);
        return result;
    }
};

迭代法实现:

迭代法更加直观,利用层序遍历,每到新到一层,就记录更新第一个节点的val即可。

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        queue<TreeNode*> que;
        int result;
        if(root != nullptr) que.push(root);
        while(!que.empty()) {
            int size = que.size();
            for(int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                if(i == 0) {
                    result = node->val;
                }
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
        }
        return result;
    }
};

112 路径总和

递归也有多种实现方式,但是不同的处理方式效率不同,本题代码随想录提供的递归方案比较优雅节省资源

通过返回bool类型数据,一旦找到满足要求的路径就可快速一路返回true,从而节省时间和内存。

至于是count减到0还是从0加到target都一样。

递归法:

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

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

迭代法使用栈模拟递归,此时栈里一个元素不仅要记录该节点指针,还要记录从头结点到该节点的路径数值总和。从而判断当前路径是否满足条件。

113 路径之和||

在112基础上进行简单修改即可,下面的代码中将path和result声明为类中的变量更节省空间,避免每次递归都创建新的局部变量。

class Solution {
public:
    void travelsal(TreeNode* cur, int count, vector<int> path, vector<vector<int>>& result) {
        if(cur->left == nullptr && cur->right == nullptr && count == 0) {
            result.push_back(path);
            return;
        }
        if(cur->left == nullptr && cur->right == nullptr) return;
        if(cur->left) {
            path.push_back(cur->left->val);
            travelsal(cur->left, count - cur->left->val, path, result);
            path.pop_back();
        }
        if(cur->right) {
            path.push_back(cur->right->val);
            travelsal(cur->right, count - cur->right->val, path, result);
            path.pop_back();
        }
        return;
    }

    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        if(root == nullptr) return {};
        vector<vector<int>> result;
        vector<int> path;
        path.push_back(root->val);
        travelsal(root, targetSum - root->val, path, result);
        return result;
    }
};

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

首先要了解基本原理:
就是以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来再切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。

那么代码应该怎么写呢?

说到一层一层切割,就应该想到了递归。

来看一下一共分几步:

第一步:如果数组大小为零的话,说明是空节点了。

第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。

第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点

第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)

第五步:切割后序数组,切成后序左数组和后序右数组

第六步:递归处理左区间和右区间

其次既然有分割,就要保持好边界值的一致性,下面保持左闭右开的原则。

使用递归进行构造。

class Solution {
private:
    TreeNode* travelsal(vector<int>& inorder, vector<int>& postorder) {
        if(postorder.size() == 0) return nullptr;

        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 = travelsal(leftInorder, leftPostorder);
        root->right = travelsal(rightInorder, rightPostorder);

        return root;
    }

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

上面的代码每次都创建了新的数组,既耗费时间又耗费空间,如果使用数组索引而不是直接创建数组的话,可以节省很多时间空间。

使用数组索引有一个隐藏的大坑,就是数组的索引已经是绝对坐标了,不用end-begin寻找相对位置!!!

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

与上一题完全一致

class Solution {
private:
    TreeNode* travelsal(vector<int>& preorder, int prebegin, int preend, vector<int>& inorder, int inbegin, int inend) {
        if(prebegin == preend) return nullptr;

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

        if(preend - prebegin == 1) return root;

        int delimiterIndex;
        for(delimiterIndex = inbegin; delimiterIndex < inend; delimiterIndex++) {
            if(inorder[delimiterIndex] == rootValue) break;
        }

        int leftInorderBegin = inbegin;
        int leftInorderEnd = delimiterIndex;
        int rightInorderBegin = delimiterIndex + 1;
        int rightInorderEnd = inend;

        int leftPreorderBegin = 1 + prebegin;
        int leftPreorderEnd = 1 + prebegin + (leftInorderEnd - leftInorderBegin);
        int rightPreorderBegin = 1 + prebegin + (leftInorderEnd - leftInorderBegin);
        int rightPreorderEnd = preend;

        root->left = travelsal(preorder, leftPreorderBegin, leftPreorderEnd, inorder, leftInorderBegin, leftInorderEnd);
        root->right = travelsal(preorder, rightPreorderBegin, rightPreorderEnd, inorder, rightInorderBegin, rightInorderEnd);

        return root;
    }

public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(inorder.size() == 0 || preorder.size() == 0) return nullptr;
        return travelsal(preorder, 0, preorder.size(), inorder, 0, inorder.size());
    }
};
posted @ 2026-03-13 11:05  遠くの君  阅读(1)  评论(0)    收藏  举报