今天是二叉树学习的第八天。主要的学习内容有:修剪二叉搜索树,将有序数组转化为二叉搜索树,以及使用反中序遍历进行累加树的转换。
669. 修剪二叉搜索树
题目链接:669. 修剪二叉搜索树 - 力扣(LeetCode)
这个题目是给出一个范围,将二叉树中不在该范围的节点进行删除。我自己的做法是构造一个中序遍历和前序遍历数组,删除数组内不符合要求的数,然后根据调整过的中序数组和后序数组构建新的二叉搜索树。也通过了,但确实挺麻烦的。具体代码实现如下:
/**
* 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:
vector<int> vec1;
vector<int> vec2;
void inorder(TreeNode* root)
{
if(root==NULL) return;
inorder(root->left);
vec1.push_back(root->val);
inorder(root->right);
}
void preorder(TreeNode* root)
{
if(root==NULL) return;
preorder(root->left);
preorder(root->right);
vec2.push_back(root->val);
}
TreeNode* construct(vector<int> inorder,vector<int> behorder)
{
if(inorder.size()==0||behorder.size()==0) return NULL;
int val=behorder[behorder.size()-1];
TreeNode* root=new TreeNode(val);
if(inorder.size()==1) return root;
int i=0;
for(i=0;i<inorder.size();i++)
{
if(inorder[i]==val) break;
}
vector<int> leftinorder(inorder.begin(),inorder.begin()+i);
vector<int> rightinorder(inorder.begin()+i+1,inorder.end());
behorder.resize(behorder.size()-1);
vector<int> leftbehorder(behorder.begin(),behorder.begin()+leftinorder.size());
vector<int> rightbehorder(behorder.begin()+leftinorder.size(),behorder.end());
root->left=construct(leftinorder,leftbehorder);
root->right=construct(rightinorder,rightbehorder);
return root;
}
TreeNode* trimBST(TreeNode* root, int low, int high) {
inorder(root);
preorder(root);
vector<int> result1;
vector<int> result2;
for(int i=0;i<vec1.size();i++)
{
if(vec1[i]>=low&&vec1[i]<=high) result1.push_back(vec1[i]);
}
for(int i=0;i<vec2.size();i++)
{
if(vec2[i]>=low&&vec2[i]<=high) result2.push_back(vec2[i]);
}
TreeNode* node=construct(result1,result2);
return node;
}
};
后来学习了随想录的题解。首先递归函数的终止条件是遇到NULL就返回NULL值,处理的过程是如果该节点小于low,就递归处理该节点的右子树并返回处理后的右子树;如果该节点大于high,就递归处理该节点的左子树并返回处理后的左子树。使用root->left和root->right接住返回值。具体代码的实现过程如下:
/**
* 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* trimBST(TreeNode* root, int low, int high) {
if(root==NULL) return NULL;
if(root->val<low)
{
TreeNode* node=trimBST(root->right,low,high);
return node;
}
if(root->val>high)
{
TreeNode* node=trimBST(root->left,low,high);
return node;
}
root->left=trimBST(root->left,low,high);
root->right=trimBST(root->right,low,high);
return root;
}
};
108.将有序数组转换为二叉搜索树
题目链接:108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)
这个题目和之前的前序中序构建二叉树思路是相似的。首先找出中间节点作为二叉搜索树的根节点,并以根节点为界划分左右子树,在递归处理左右子树即可。具体代码实现如下:
/**
* 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* order(vector<int> nums,int left,int right)
{
if(left>right) return NULL;
int mid=left+(right-left)/2;
TreeNode* root=new TreeNode(nums[mid]);
root->left=order(nums,left,mid-1);
root->right=order(nums,mid+1,right);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
TreeNode* result=order(nums,0,nums.size()-1);
return result;
}
};
538.把二叉搜索树转换为累加树
题目链接:538. 把二叉搜索树转换为累加树 - 力扣(LeetCode)
这个题目的要求是将二叉搜索树每个结点的值更新为一个逆向的累加和。如下图例子所示:
我自己的做法是中序遍历得到一个数组,然后翻转之后进行累加求和,再通过一个中序遍历进行每个节点值的更新。具体代码实现如下:
/**
* 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:
vector<int> vec;
vector<int> result;
int i=0;
void order(TreeNode* root)
{
if(root==NULL) return;
order(root->left);
vec.push_back(root->val);
order(root->right);
}
void add(TreeNode* root)
{
if(root==NULL) return;
add(root->left);
root->val=result[i++];
add(root->right);
}
TreeNode* convertBST(TreeNode* root) {
if(root==NULL) return NULL;
order(root);
reverse(vec.begin(),vec.end());
result.push_back(vec[0]);
for(int i=1;i<vec.size();i++)
{
result.push_back(result[i-1]+vec[i]);
}
reverse(result.begin(),result.end());
add(root);
return root;
}
};
后来看了代码随想录的题解。直接使用逆中序遍历,即右中左的遍历方法,通过双指针进行节点的值的更新。这样实现的效率更高,代码也更加简洁。具体代码实现如下:
/**
* 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* pre=NULL;
void order(TreeNode* root)
{
if(root==NULL) return;
order(root->right);
if(pre!=NULL) root->val=pre->val+root->val;
pre=root;
order(root->left);
}
TreeNode* convertBST(TreeNode* root) {
order(root);
return root;
}
};