LeetCode[105/106/112]从前序与中序遍历序列构造二叉树、 从中序与后序遍历序列构造二叉树、路径总和 C/C++——Week 2 III

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

题目描述[中等]:

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
示例1:
输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]

输出: [3,9,20,null,null,15,7]
1

思路[递归]:

我们看示例1的树,我们知道了他的前序遍历序列是: [3,9,20,15,7];中序遍历序列是: [9,3,15,20,7];
通过观察我们可知根节点为3,左子树的中序遍历为[9],右子树中序遍历[15,20,7];我们通过前序遍历可以左子树的前序遍历为[9];右子树前序遍历[20,15,7]。那我们就可以通过左右子树前序中序遍历递归来实现二叉树的构建。
注意:每次递归后,都需要在中序序列中找到当前根节点所在的下标,为提高效率,我们可以构建一个哈希表,用来存放所有节点再中序序列中的位置。这样就可以把查找的时间从O(n)->O(1)。

C++代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
    
    
    //定义一个哈希表
    unordered_map<int, int> pos;

public:
    TreeNode* Build(const vector<int>& preorder, const vector<int>& inorder, int pl, int pr, int il, int ir) {
    
    
        if (pl > pr || il > ir) {
    
    
            return nullptr;
        }
        //左子树中的节点数目=当前节点在中序序列的位置-中序序列的起始下标
        int k = pos[preorder[pl]] - il;
        
        // 建立根节点        
        TreeNode* root = new TreeNode(preorder[pl]);

     
        // 递归地构造左子树,并连接到根节点
        // 先序遍历中「从 左边界+1 开始的 k」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
        root->left = Build(preorder, inorder, pl + 1, pl + k, il, il + k - 1);
        // 递归地构造右子树,并连接到根节点
        // 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
         root->right = Build(preorder, inorder, pl + k + 1, pr, il + k + 1, ir);
        return root;
    }

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
    
    
        //获取节点个数n
        int n = preorder.size();
        //通过哈希表来存储中序序列节点位置
        for (int i = 0; i < n; i++) {
    
    
            pos[inorder[i]] = i;
        }
        //调用二叉树的构建,切片操作
        return Build(preorder, inorder, 0, n - 1, 0, n - 1);
    }
};

时间/空间复杂度:O(n);

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

题目描述[中等]:

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

示例1:
输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]

输出:[3,9,20,null,null,15,7]
2

思路[递归]:

本题以示例1为例,他的中序序列为:[9,3,15,20,7],后序序列为[9,15,7,20,3];根据这两个序列的性质,我们可知后序序列的最后一个元素为根节点,那么通过中序序列,我们可知左子树的中序遍历为[9];右子树的中序遍历为[15,20,7]。所以左子树的后序序列为9,右子树的后序序列为:[15,7,20]。我们通过这些序列可以递归来构建左右子树,从而构建二叉树。

C++代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
    
    
     //定义一个哈希表
    unordered_map<int, int> pos;
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
    
    
     //获取节点个数n
        int n = inorder.size();
        //通过哈希表来存储中序序列节点位置
        for (int i = 0; i < n; i++) {
    
    
            pos[inorder[i]] = i;
        }
        //调用二叉树的构建,切片操作
        return Build(inorder, postorder, 0, n - 1, 0, n - 1);
    }
       TreeNode* Build(vector<int>& inorder,  vector<int>& postorder, int il, int ir, int pl, int pr) {
    
    
        if (pl > pr || il > ir) {
    
    
            return nullptr;
        }
        //左子树中的节点数目=当前节点在中序序列的位置-后序序列的末下标
        int k = pos[postorder[pr]] - il;
        
        // 建立根节点        
        TreeNode* root = new TreeNode(postorder[pr]);

     
        // 递归地构造左子树,并连接到根节点
        // 先序遍历中「从 左边界 开始的 k - 1」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
        root->left = Build(inorder, postorder,il, il + k - 1, pl, pl + k - 1);
        // 递归地构造右子树,并连接到根节点
        // 先序遍历中「从 左边界+左子树节点数目+1 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位 到 右边界-1」的元素
         root->right = Build(inorder, postorder, il + k + 1, ir, pl + k , pr - 1);
        return root;
    }
};

时间/空间复杂度:O(n);

112.路径总和

题目描述[简单]:

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。

叶子节点 是指没有子节点的节点。
示例1:
3

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22

输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。

思路[递归]:

本题判断本质就是在左子树或右子树找到一条路径长度为target的值的路径。
将题目转换成:target == root->val

C++代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
    
    
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
    
    
        if(root == nullptr)
        return false;
        if(root -> left == nullptr && root -> right == nullptr)
        return root->val == targetSum;
        return hasPathSum(root->left,targetSum - root->val) || hasPathSum(root->right,targetSum - root->val);
    }
};

时间/空间复杂度:O(n);

猜你喜欢

转载自blog.csdn.net/Lailalalala/article/details/126161062
今日推荐