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的树,我们知道了他的前序遍历序列是: [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]
思路[递归]:
本题以示例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:
输入: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);