二叉树第二期
二叉树的关键思路:把题目的要求细化,搞清楚根节点应该做什么,然后剩下的事情抛给前、中、后序遍历框架即可。
01 构造最大二叉树
给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:
创建一个根节点,其值为 nums 中的最大值。
递归地在最大值 左边 的 子数组前缀上 构建左子树。
递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums 构建的 最大二叉树 。
输入:nums = [3,2,1,6,0,5]输出:[6,3,5,null,2,0,null,null,1]解释:递归调用如下所示:- [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。- [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。- 空数组,无子节点。- [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。- 空数组,无子节点。- 只有一个元素,所以子节点是一个值为 1 的节点。- [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。- 只有一个元素,所以子节点是一个值为 0 的节点。- 空数组,无子节点。来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/maximum-binary-tree著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
函数签名如下:
TreeNode* constructMaximumBinaryTree(vector<int>& nums);
先明确根节点需要做什么?对于构造二叉树的问题,根节点要做的就是把自己构造出来。
需要遍历数组把最大值 maxVal 找出来,把根节点 root 做出来,然后堆 maxVal 左边数组和右边数组进行递归调用,作为 root 的左右子树。
比如,输入数组 [3, 2, 1, 6, 0, 5],对于整棵树的根节点来说,其实在做这件事:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
if (nums is empty)
return nullptr;
// 找到数组中的最大值
int maxVal = nums[0];
int index = 0;
for (int i = 0; i < nums.size(); ++i) {
if (nums[i] > maxVal) {
maxVal = nms[i];
index = i;
}
}
TreeNode* root = new TreeNode(maxVal);
// 递归调用构造左右子树
root->left = constructMaximumBinary(nums[0..index - 1]);
root->left = constructMaximumBinary(nums[index + 1..nums.size() - 1]);
return root;
}
对于每个节点,只需要找到当前 nums 中的最大值和对应的索引,然后递归调用左右数组构造左右子树即可。
构建一个辅助函数 build,来控制 nums 的索引:
// 将 nums[low..high] 构造成符合条件的树,返回跟节点
TreeNode* build(vector<int>& nums, int low, int high) {
if (low > high) {
return nullptr;
}
// 找到数组中的最大值和对应的索引
int index = low;
int maxVal = nums[index];
for (int i = low; i <= high; ++i) {
if (maxVal < nums[i]) {
index = i;
maxVal = nums[i];
}
}
TreeNode* root = new TreeNoed(maxVal);
root->left = build(nums, low, index - 1);
root->right = build(nums, index + 1, high);
return root;
}
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
return build(nums, 0, nums.size() - 1);
}
// 或者
class Solution {
public:
int getMaxIndex(vector<int>& nums) {
int index = 0;
int maxV = nums[index];
for (int i = 1; i < nums.size(); ++i) {
if (maxV < nums[i]) {
maxV = nums[i];
index = i;
}
}
return index;
}
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
if (nums.empty())
return nullptr;
int maxIndex = getMaxIndex(nums);
int maxV = nums[maxIndex];
TreeNode* root = new TreeNode(maxV);
if (nums.size() == 1) {
return root;
}
// 注意 index 范围大小
if (maxIndex > 0) {
vector<int> numsLeft(nums.begin(), nums.begin() + maxIndex);
root->left = constructMaximumBinaryTree(numsLeft);
}
if (maxIndex < nums.size()) {
vector<int> numsRight(nums.begin() + maxIndex + 1, nums.end());
root->right = constructMaximumBinaryTree(numsRight);
}
return root;
}
};
02 通过前序和中序遍历结果构造二叉树
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]
示例 2:
输入: preorder = [-1], inorder = [-1]
输出: [-1]
提示:
1 <= preorder.length <= 3000
inorder.length == preorder.length
-3000 <= preorder[i], inorder[i] <= 3000
preorder 和 inorder 均 无重复 元素
inorder 均出现在 preorder
preorder 保证 为二叉树的前序遍历序列
inorder 保证 为二叉树的中序遍历序列
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
代码如下:
// 直接操作索引:注意索引变化。左闭右闭
class Solution {
public:
TreeNode* build(vector<int>& preorder, int preStart, int preEnd, vector<int>& inorder, int inStart, int inEnd) {
if (preStart > preEnd) {
return nullptr;
}
// root 节点对应的值就是前序遍历数组的第一个元素
int rootVal = preorder[preStart];
int index = 0;
for (int i = inStart; i <= inEnd; ++i) {
if (inorder[i] == rootVal) {
index = i;
rootVal = inorder[i];
}
}
TreeNode* root = new TreeNode(rootVal);
root->left = build(preorder, preStart + 1, preStart + index - inStart, inorder, inStart, index - 1);
root->right = build(preorder, preStart + index - inStart + 1, preEnd, inorder, index + 1, inEnd);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return build(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size() - 1);
}
};
// 新建数组:注意数组长度,如果为 1,直接返回。左闭右开
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (preorder.empty())
return nullptr;
int rootVal = preorder[0];
TreeNode* root = new TreeNode(rootVal);
if (preorder.size() == 1) {
return root;
}
int delimiterIndex = 0;
for (int i = 0; i < inorder.size(); ++i) {
if (inorder[i] == rootVal) {
delimiterIndex = i;
break;
}
}
vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end());
vector<int> leftPreorder(preorder.begin() + 1, preorder.begin() + leftInorder.size() + 1);
vector<int> rightPreorder(preorder.begin() + leftInorder.size() + 1, preorder.end());
root->left = buildTree(leftPreorder, leftInorder);
root->right = buildTree(rightPreorder, rightInorder);
return root;
}
};
