方法论
构造二叉树题目一般都是用数组构造,可以两个数组或者一个数组构造。
用两个数组构造一棵二叉树的递归函数需要四个参数,每个数组都要指定起始和结束位置:
TreeNode* build(vector<int>& inorder, int inbegin, int inend, vector<int>& postorder, int postbegin, int postend){}
题目包括:
LT106 从中序与后序遍历序列构造二叉树
LT105 从前序与中序遍历序列构造二叉树
用一个数组构造一棵二叉树只需要2个参数,指定起始和结束位置:
TreeNode* build(vector<int>& nums, int begin, int end){}
题目包括:
LT654 最大二叉树
LT108 有序数组转换为二叉搜索树
不管是几个数组,最终的代码写法都是很相似的。分为几个步骤:
1.找到分割点,也就是根节点
2.切割数组,如果是两个数组的,需要分别切割
3.递归构造左右子树,递归函数的返回值给root节点
另外代码编写过程中要坚持循环不变量原则,统一使用左闭右开原则。
LT106 从中序与后序遍历序列构造二叉树
循环不变量:左闭右开
方法一:使用临时数组,这种方法空间复杂度比较大,时间复杂度也大,容易超时
注意类似用数组构造二叉树的题目,每次分隔尽量不要定义新的数组,而是通过下表索引直接在原数组上操作,这样可以节约时间和空间上的开销。
/**
* 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:
TreeNode* build(vector<int>& inorder, vector<int>& postorder){
cout << endl << "inorder:";
for(auto &it:inorder)
cout << "," << it;
cout << endl << "postorder:";
for(auto &it:postorder)
cout << "," << it;
if(inorder.size() == 0 || postorder.size() == 0) return NULL;
TreeNode* root = new TreeNode(postorder[postorder.size() - 1]);
if(postorder.size() == 1){
return root;
}
//找到中序数组的切割点
int i = 0;
for(; i < inorder.size(); i++){
if(inorder[i] == postorder[postorder.size() - 1])
break;
}
//拆分中序数组:中左和中右
vector<int> inleft(inorder.begin(), inorder.begin() + i);
vector<int> inright(inorder.begin() + i + 1, inorder.end());
//拆分后序数组:后左和后右
postorder.resize(postorder.size() - 1);
vector<int> postleft(postorder.begin(), postorder.begin() + inleft.size());
vector<int> postright(postorder.begin() + inleft.size(), postorder.end());
//递归处理中左和后左、中右和后右
root->left = build(inleft, postleft);
root->right = build(inright, postright);
cout << "end..."<<endl; //只会执行一次,返回的就是整棵树的root节点
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
return build(inorder, postorder);
}
};
使用下标索引:
/**
* 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:
unordered_map<int, int> inordermap; //存储中序数组中值和下标的映射关系
TreeNode* build(vector<int>& inorder, int inbegin, int inend, vector<int>& postorder, int postbegin, int postend){
cout << "inbegin:" << inbegin << ",inend:" << inend << ",postbegin:" << postbegin << ",postend:" << postend << endl;
if(postbegin == postend) return NULL;
TreeNode* root = new TreeNode(postorder[postend - 1]);
if(postend - postbegin == 1) return root;
//1.找到中序数组的切割点
int i = inordermap[postorder[postend - 1]];
//2.拆分中序数组,左闭右开,中左[inleftbegin, inleftend)和中右[inrightbegin, inrightend)
int inleftbegin = inbegin;
int inleftend = i;
int inrightbegin = i + 1;
int inrightend = inend;
//3.拆分后序数组,左闭右开,后左[postleftbegin, postleftend)和后右[postrightbegin, postrightend)
int postleftbegin = postbegin;
int postleftend = postleftbegin + (i - inbegin);
int postrightbegin = postleftend; //注意这里不是postleftend+1
int postrightend = postend - 1;
//4.递归处理中左和后左、中右和后右
root->left = build(inorder, inleftbegin, inleftend, postorder, postleftbegin, postleftend);
root->right = build(inorder, inrightbegin, inrightend, postorder, postrightbegin, postrightend);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
int idx = 0;
for(auto &it : inorder)
inordermap[it] = idx++;
return build(inorder, 0, inorder.size(), postorder, 0, postorder.size());
}
};
LT105 从前序与中序遍历序列构造二叉树
/**
* 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:
unordered_map<int, int> inordermap;
TreeNode* build(vector<int>& inorder, int inbegin, int inend, vector<int>& preorder, int prebegin, int preend){
cout << "inbegin:"<<inbegin<<",inend:"<<inend<<",prebegin:"<<prebegin<<",preend:"<<preend<<endl;
if(prebegin == preend) return NULL;
TreeNode* root = new TreeNode(preorder[prebegin]);
if(preend - prebegin == 1) return root;
//找到中序数组的切割点
int i = inordermap[preorder[prebegin]];
//拆分中序数组,中左和中右
int inleftbegin = inbegin;
int inleftend = i;
int inrightbegin = i + 1;
int inrightend = inend;
//拆分前序数组,前左和前右
int preleftbegin = prebegin + 1;
int preleftend = preleftbegin + (i - inbegin);
int prerightbegin = preleftend;
int prerightend = preend;
//递归处理中左和前左、中右和前右
root->left = build(inorder, inleftbegin, inleftend, preorder, preleftbegin, preleftend);
root->right = build(inorder, inrightbegin, inrightend, preorder, prerightbegin, prerightend);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int idx = 0;
for(auto &it : inorder){
inordermap[it] = idx++;
}
return build(inorder, 0, inorder.size(), preorder, 0, preorder.size());
}
};
LT654 最大二叉树
给定一个不含重复元素的整数数组 nums 。一个以此数组直接递归构建的 最大二叉树 定义如下:
二叉树的根是数组 nums 中的最大元素。
左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树。
右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树。
返回有给定数组 nums 构建的 最大二叉树 。
/**
* 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:
TreeNode* build(vector<int>& nums, int begin, int end){
if(begin == end) return NULL;
//找到[begin, end)范围最大值的下标maxvalueidx
int maxvalue = nums[begin];
int maxvalueidx = begin;
int i = begin;
for(; i < end; i++){
if(nums[i] > maxvalue){
maxvalue = nums[i];
maxvalueidx = i;
}
}
TreeNode* root = new TreeNode(nums[maxvalueidx]);
if(end - begin == 1) return root;
//左子树
int leftbegin = begin;
int leftend = maxvalueidx;
//右子树
int rightbegin = maxvalueidx + 1;
int rightend = end;
//分别递归处理左子树、右子树
root->left = build(nums, leftbegin, leftend);
root->right = build(nums, rightbegin, rightend);
return root;
}
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
return build(nums, 0, nums.size());
}
};
LT108 有序数组转换为二叉搜索树
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
思路:因为数组本身就是有序的,每次选择中间的节点作为根节点,构造出来的肯定就是二叉搜索树,那是不是就平衡呢?仔细想一想,构成平衡树是自然而然的事情,因为每次选择中间元素,左右的个数都是相同的,最多差一个。
/**
* 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:
TreeNode* build(vector<int>& nums, int begin, int end){
if(begin == end) return NULL;
//找到分割点
int i = (end - begin)/2 + begin;
TreeNode* root = new TreeNode(nums[i]);
//左子树
int leftbegin = begin;
int leftend = i;
//右子树
int rightbegin = i + 1;
int rightend = end;
//递归构造子子树和右子树
root->left = build(nums, leftbegin, leftend);
root->right = build(nums, rightbegin, rightend);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
return build(nums, 0, nums.size());
}
};