修剪二叉搜索树
在给定二叉搜索树的根节点root的同时,给定最小边界low和最大边界high,通过修剪二叉搜索树,使得所有节点值在[low,high]中。
逐个删除
我的想法,范围外的节点全部删除,参考昨日二叉搜索树节点的删除操作,但由于每次都需要遍历,导致时间复杂度为O(n)。代码如下:
class Solution {
public:
TreeNode* find_parent(TreeNode* root, int key) {
if (root == nullptr || (root->left == nullptr && root->right == nullptr)) {
return nullptr; // 如果当前节点为空或为叶节点,返回nullptr
}
if (root->left != nullptr && root->left->val == key) {
return root; // 如果左子节点的值等于key,返回当前节点作为父节点
}
if (root->right != nullptr && root->right->val == key) {
return root; // 如果右子节点的值等于key,返回当前节点作为父节点
}
if (key < root->val) {
return find_parent(root->left, key); // 如果key小于当前节点的值,递归地在左子树中查找
} else {
return find_parent(root->right, key); // 如果key大于或等于当前节点的值,递归地在右子树中查找
}
}
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == nullptr) return nullptr;
if (root->val == key) {
// 要删除的节点是根节点
if (root->left == nullptr) return root->right; // 只有右子树
if (root->right == nullptr) return root->left; // 只有左子树
// 有两个子节点,找到右子树的最小节点
TreeNode* minNode = getMin(root->right);
root->val = minNode->val; // 将右子树的最小节点的值赋给当前节点
root->right = deleteNode(root->right, minNode->val); // 删除右子树中的最小节点
} else if (key < root->val) {
root->left = deleteNode(root->left, key); // 在左子树中递归删除
} else {
root->right = deleteNode(root->right, key); // 在右子树中递归删除
}
return root;
}
TreeNode* getMin(TreeNode* node) {
while (node->left != nullptr)
node = node->left;
return node;
}
TreeNode* trimBST(TreeNode* root, int low, int high) {
if (root == nullptr) {
return nullptr;
}
// 否则,递归修剪左右子树
root->left = trimBST(root->left, low, high);
root->right = trimBST(root->right, low, high);
// 如果当前节点的值不在[low, high]范围内,则删除该节点
if (root->val < low || root->val > high) {
TreeNode* newRoot = deleteNode(root, root->val); // 删除当前节点,并获取新的根节点
return trimBST(newRoot, low, high); // 递归修剪新的树
}
return root;
}
};
注意这里是用后序遍历,而非之前的前序遍历,后序遍历使得每次都从底部开始删,能避免前序导致的部分节点无法删除。
递归法
注意此处当某节点左孩子不符合时范围时,并不能直接返回nullptr,而应将左孩子的右孩子return,同理,当某节点右孩子不符合范围时,需return右孩子的左孩子。
class Solution {
public:
TreeNode* trimBST(TreeNode* root, int low, int high) {
if (root == nullptr) {
return nullptr;
}
// 删除不在范围内的节点
if (root->val < low) {
return trimBST(root->right, low, high); // 递归修剪右子树
} else if (root->val > high) {
return trimBST(root->left, low, high); // 递归修剪左子树
}
// 递归修剪左右子树
root->left = trimBST(root->left, low, high);
root->right = trimBST(root->right, low, high);
return root;
}
};
算法的时间复杂度和空间复杂度为O(logn)
释放空间写法,会报错。
TreeNode* trimBST(TreeNode* root, int low, int high) {
if (root == nullptr) {
return nullptr;
}
// 如果节点值不在[low, high]范围内,删除节点并释放空间
if (root->val < low) {
TreeNode* rightSubtree = trimBST(root->right, low, high);
delete root; // 释放当前节点的内存
return rightSubtree; // 返回修剪后的右子树
} else if (root->val > high) {
TreeNode* leftSubtree = trimBST(root->left, low, high);
delete root; // 释放当前节点的内存
return leftSubtree; // 返回修剪后的左子树
}
// 递归修剪左右子树
root->left = trimBST(root->left, low, high);
root->right = trimBST(root->right, low, high);
return root;
}
将有序数组转换为二叉搜索树
108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)
递归法
先写终止方法,当数组为空时,return nullptr,找寻中位设置为根,将数组分为左右两部分,并带入遍历左右节点。最后返回。
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums, int start, int end) {
if(start > end)
return nullptr;
int mid = start + (end - start) / 2; // 防止溢出
TreeNode* root = new TreeNode(nums[mid]);
root->left = sortedArrayToBST(nums, start, mid - 1);
root->right = sortedArrayToBST(nums, mid + 1, end);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
return sortedArrayToBST(nums, 0, nums.size() - 1);
}
};
算法的时间复杂度为O(n),空间复杂度为O(log(n))。
把二叉搜索树转换为累加数
538. 把二叉搜索树转换为累加树 - 力扣(LeetCode)
很巧妙的思路,反转中序遍历,右中左的顺序,累加数即累加每个节点的值即可。
class Solution {
public:
int sum = 0;
TreeNode* convertBST(TreeNode* root) {
if(root == nullptr){
return nullptr;
}
convertBST(root->right);
sum += root->val;
root->val = sum;
convertBST(root->left);
return root;
}
};
算法的时间复杂度为O(n),空间复杂度为O(n)。

1020

被折叠的 条评论
为什么被折叠?



