您的位置:首页 > 其它

14. 构造二叉树

2022-05-28 00:43 1596 查看

title: 构造二叉树 , 看这一篇就足够! 思想:构造整棵树 = 根节点 + 构造左子树 + 构造右子树

📃 题目一描述

题目链接:从中序与后序遍历构造二叉树

🔔 解题思路

必须明确条件:给出一个数组的值中,是没有重复的数字的,即没用节点的数值是相同的!

画图分析:(图来自dong哥)

可以很明确得知:后续遍历数组中postEnd就是中点的值,通过中点的值我们就可以在中序遍历数组中找到中点的位置,从而分割出左子树,右子树,递归就可以完成构建;

class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
return build(inorder, 0, inorder.size() - 1, postorder, 0, postorder.size() - 1);
}

//都是不同的值组成,不存在“中”在左子树中出现的情况;
TreeNode* build(vector<int>& inorder, int inStart, int inEnd, vector<int>& postorder, int postStart, int postEnd) {
if (inStart > inEnd) return nullptr;

int rootVal = postorder[postEnd];
int size = 0;
for (int i = inStart; i <= inEnd; i++) {
if (rootVal == inorder[i]) { // 找到中序遍历“左 中 右” 的 “中”;
size = i - inStart; // 记录左的长度,需要使用其长度求其他下标 =》 因为起点不一定是从0开始,要用相对值
break;
}
}

//构建中节点,左右子树
TreeNode *root =  new TreeNode(rootVal);
root->left = build(inorder, inStart, inStart + size - 1, postorder, postStart, postStart + size - 1);
root->right = build(inorder, inStart + size + 1, inEnd, postorder, postStart + size, postEnd - 1);
return root;
}
};

📃 题目二描述

题目链接:从前序与中序遍历构造二叉树

🔔 解题思路

同上,依据图来写代码即可:

class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return build(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size() - 1);
}

TreeNode* build(vector<int>& preorder, int preStart, int preEnd, vector<int>& inorder, int inStart, int inEnd) {
if (preStart > preEnd) return nullptr;

int rootVal = preorder[preStart];
int size = 0;
for (int i = inStart; i <= inEnd; i++) {
if (inorder[i] == rootVal) {
size = i -inStart;
break;
}
}

// 开始构建树
TreeNode* root = new TreeNode(rootVal);
root->left = build(preorder, preStart + 1, preStart + size, inorder, inStart, inStart + size - 1);
root->right = build(preorder, preStart + size + 1, preEnd, inorder, inStart + size + 1, inEnd);
return root;
}
};

📃 题目三描述

题目链接:根据前序和后序遍历构造二叉树

🔔 解题思路

这道题与前两道题的不同之处:通过前序和后序是无法确定唯一一颗二叉树的!

原因:看图

前序和后序只能确定中,无法确定左右的边界!可能压根就没有左指针或者右指针 例如:

preorder = [1,2,3], postorder = [3,2,1]
,而下图两种树结构都满足;

理解:我们假设前序遍历的第二个元素是左子树的根节点(左图),但实际上左子树有可能是空指针(右图),那么这个元素就应该是右子树的根节点。由于这里无法确切进行判断,所以导致了最终答案的不唯一。

这道题如何做:**①确定根节点,②将前序遍历数组中根节点后的下一位为左根节点(preStart + 1, 自己也快选定其他), ③在后序遍历数组中找到该左根节点的位置,从而分割左右子树;**如图:

代码:

class Solution {
public:
TreeNode* constructFromPrePost(vector<int>& preorder, vector<int>& postorder) {
return build(preorder, 0, preorder.size() - 1, postorder, 0, postorder.size() - 1);
}
TreeNode* build(vector<int>& preorder, int preStart, int preEnd, vector<int>& postorder, int postStart, int postEnd) {
if (preStart > preEnd) return nullptr;

int rootVal = preorder[preStart];
if (preStart == preEnd) return new TreeNode(rootVal);
int leftRootVal = preorder[preStart + 1];
int size = 0;
for (int i = postStart; i <= postEnd; i++) {
if (postorder[i] == leftRootVal) {
size = i - postStart;
break;
}
}

//构建二叉树
TreeNode* root = new TreeNode(rootVal);
root->left = build(preorder, preStart + 1, preStart + size + 1, postorder, postStart, postStart + size);
root->right = build(preorder, preStart + size + 2, preEnd, postorder, postStart + size + 1, postEnd);
return root;
}
};

优化建议:以上三题,均是不重复数组,可以用空间换时间的想法:可以采用哈希表记录 需要遍历的数组 对应的index, 这样在每次遍历的时候可以直接得到想要查询数的下标

📃 题目四描述(简单练手题)

题目链接:最大二叉树

🔔 解题思路

根据构造树的思想,依题目构造即可

class Solution {
public:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
return build(nums, 0, nums.size() - 1);
}
TreeNode* build(vector<int>& nums, int start, int end) {
if (start > end) return nullptr;

int rootVal = INT_MIN;
int index = 0;
for (int i = start; i <= end; i++) {
if (rootVal < nums[i]) {
index = i;
rootVal = nums[i];
}
}

//构建树
TreeNode* root = new TreeNode(rootVal);
root->left = build(nums, start, index - 1);
root->right = build(nums, index + 1, end);
return root;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: