输入:两个整数数组 preorder(前序遍历)和 inorder(中序遍历)
要求:根据这两个序列构造二叉树 preorder 和 inorder 均无重复元素
输出:构造出的二叉树的根节点
思路:这道题乍一看有些棘手,但既然涉及到 “构造二叉树”,第一时间就应该联想到 递归(分治法)。
我们可以试着模拟人脑还原树的过程:
-
定位根节点:拿到题目,我们怎么知道谁是根?显然,前序遍历 告诉了我们“谁是头”(第一个元素)。
-
划分势力范围:知道根是谁后,去 中序遍历 里找到它的位置。这一找,瞬间就清晰了——根节点左边的所有元素属于 左子树,右边的所有元素属于 右子树。
-
递归的传递:既然父节点能这么分,子节点当然也能这么分。这是一个典型的“子问题”结构。
-
确立返回值:题目要求返回整棵树的
TreeNode*,那么我们的递归函数也应当返回当前子树的根节点TreeNode*。
一句话总结:前序遍历负责 “提头”(确定根),中序遍历负责 “切分”(确定左右子树长度)。把这个逻辑想通了,递归函数的写法也就呼之欲出了。
利用前序和中序遍历的特性进行递归拆解:
-
找根节点:前序遍历的第一个元素
pre[0]一定是当前的根节点。 -
切分左右子树:拿着这个根节点的值,去中序遍历里找它的位置。
-
中序序列中,根节点左边的所有数构成了左子树。
-
中序序列中,根节点右边的所有数构成了右子树。
-
-
递归构建:
-
根据中序遍历中算出的左子树长度,在前序遍历中也能切分出对应的左子树部分(紧跟在根节点后面)。
-
既然拿到了左右子树各自的
preorder和inorder序列,就可以递归生成左节点和右节点。
-
复杂度:
时间复杂度:O(N^2) //使用了vector的拷贝 进阶写法肯定是引用而不是拷贝
空间复杂度:O(N^2) //使用了vector的拷贝 进阶写法肯定是引用而不是拷贝
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return tree(preorder, inorder);
}
TreeNode* tree(vector<int> pre, vector<int> in) {
if (pre.empty()) {
return nullptr;
}
TreeNode* tmp = new TreeNode(pre[0]);
vector<int> preleft,inleft,preright,inright;
int i = 0;
for (; i < in.size(); i++) {
if (in[i] == pre[0]) {
break;
}
inleft.push_back(in[i]);
}
i += 1;
for (; i < in.size(); i++) {
inright.push_back(in[i]);
}
int j = 1;
for (int k = 0; k < inleft.size(); k++) {
preleft.push_back(pre[j++]);
}
for (int k = 0; k < inright.size(); k++) {
preright.push_back(pre[j++]);
}
tmp->left = tree(preleft, inleft);
tmp->right = tree(preright, inright);
return tmp;
}
};
6305

被折叠的 条评论
为什么被折叠?



