代码随想录训练营Day23 | Leetcode 669、108、538
一、669 修剪二叉搜索树
题目链接:669 修剪二叉搜索树
核心:明确遇到待修剪的节点时应该如何操作
(1)当前节点值小于low,说明需要被修剪,还需要在其右子树寻找是否还存在要修剪的节点,直到遍历到的节点在区间内,无需修剪,此时将right返回到待修剪节点的上一层,即right会链接到被修剪节点的上一层;
(2)当前节点值大于high,说明需要被修剪,还需在其左子树寻找是否还存在要修剪的节点,直到遍历到符合区间要求的节点,此时无需修剪,并将left返回到待修剪节点的上一层;
(3)当前节点值符合区间要求,无需修剪,此时需要分别递归左、右子树寻找要修剪的节点。
注意:最后返回根节点root。
TreeNode* trimBST(TreeNode* root, int low, int high) {
//递归法:
if(!root)
return nullptr;
//当前root是需要被修剪的,并在root右子树寻找符合区间[low,high]的节点
if(root->val < low)
{//root右子树上符合区间要求的节点right被返回到root的上一层(因为root被移除)
TreeNode* right=trimBST(root->right,low,high);
return right;
}
//当前root也是要被修剪,并在root左子树寻找符合区间的节点
else if(root->val > high)
{//root左子树符合区间要求的节点left被返回至root的上一层
TreeNode* left=trimBST(root->left,low,high);
return left;
}
//当前root符合区间要求,无需修剪,需递归遍历左、右子树确定要修剪的节点
root->left=trimBST(root->left,low,high); //该root左孩子实质是接住right
root->right=trimBST(root->right,low,high);
return root; //此时返回的依然是根节点
}
二、108 将有序数组转换为二叉搜索树
题目链接:108 将有序数组转换为二叉搜索树
核心:已知二叉搜索树的中序遍历数组是有序的(左中右),那么有序数组的中间元素一定是根节点root。
第一,由数组中间元素构造根节点;
第二,由左右区间分别递归构造左、右子树。
//左闭右闭区间[left,right]
TreeNode* traversal(vector<int>& nums,int left,int right)
{//递归函数,先以中点为root,然后分割数组分别构造左右子数
if(left>right)
return nullptr; //区间为空,即nums为空
//1。构造中点为root
int mid=left+(right-left)/2;
TreeNode* root=new TreeNode(nums[mid]);
//2.分别递归构造左右子树,注意左右区间的取值
root->left=traversal(nums,left,mid-1);
root->right=traversal(nums,mid+1,right);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
return traversal(nums,0,nums.size()-1); //注意是左闭右闭区间
}
三、538 把二叉搜索树转换为累加树
题目链接:538 把二叉搜索树转换为累加树
核心:由于二叉搜索树的中序遍历是有序的,且从小到大,故本题实质是将中序遍历数组从后往前累加,直到数组的第一个元素,即按照反中序遍历进行累加,也就是说如果按照反中序(右中左)遍历二叉搜索树,只需从前往后累加即可,就是当前节点值为当前节点值和前一个节点值的累加。
具体实现方式有递归法和迭代法,两种方法都需要定义一个pre记录前一个节点值,以及每次累加结束需要更新pre。
/*
int pre=0;
void traversal(TreeNode* node)
{//递归函数:右中左
if(!node)
return; //记录前一个节点值
traversal(node->right); //右
node->val+=pre; //中
pre=node->val; //更新pre
traversal(node->left); //左
}
*/
TreeNode* convertBST(TreeNode* root) {
//迭代法:借助栈实现反中序遍历(右中左)
stack<TreeNode*> stk;
TreeNode* cur=root; //记录当前节点
int pre=0; //记录前一个节点值
while(cur || !stk.empty())
{
if(cur)
{
stk.push(cur);
cur=cur->right; //右
}
else
{//cur==nullptr
cur=stk.top(); //中
stk.pop();
cur->val+=pre; //前一个节点值累加到当前节点
pre=cur->val; //更新pre
cur=cur->left; //左
}
}
return root;
/*
//实质是中序遍历数组从后往前累加,等价于反中序遍历数组从前往后累加
//递归法:反中序,右中左
pre=0;
traversal(root);
return root;
*/
}