LeetCode连接:BST
0 BST核心内容
0.二叉树的核心内容 +
1.基本性质:左子树都小于根,右子树都大于根。
2.重要性质:BST的中序遍历序列递增有序
1 二叉搜索树的定义
典例 验证BST树
题目:给出一个二叉树,验证其是否是BST。
思路:
方法一:利用BST的“重要性质”:BST的中序遍历序列递增有序。中序遍历此二叉树,判断是否递增有序。
vector<int> vec;
void inOrder(TreeNode* root){
if(root == nullptr ) return;
inOrder(root->left);
vec.push_back(root->val);
inOrder(root->right);
}
bool isValidBST(TreeNode* root) {
inOrder(root);
for(int i = 0;i < vec.size()-1;++i) if(vec[i] >= vec[i+1]) return false;
return true;
}
方法二:利用BST的“基本性质”:左子树都比根小,右子树都比根大。
误区:最开始一直想的是求出左右子树的最大最小值,先求出子树的最值,然后和根比较,是 “自底向上” 的后序思想。但实现过程中涉及到大量的重复计算,而且终点设计比较麻烦。
既然“自底向上”不行,那就换用 “自顶向下”的先序思想,将合法的区间传下去,这样只用在子树判断是否合法就行了。
// 方法一: 从根节点传一个合法区间下去,判断树是否在合法区间内
bool isOk(TreeNode* root,long long low,long long high){
if(root == nullptr) return true;
// 先判断根是否满足
if(root->val <= low || root->val >= high) return false;
if(isOk(root->left,low,root->val) == false) return false;
return isOk(root->right,root->val,high);
}
bool isValidBST(TreeNode* root) {
return isOk(root,LONG_MIN,LONG_MAX);
}
2 BST的基本操作
2.1 BST的查找
2.2 BST的插入
在查找为 null 时插入。
void insert(TreeNode*& root,int val){
if(root == nullptr){
root = new TreeNode(val);
return ;
}
if(root->val > val) insert(root->left,val);
else insert(root->right,val);
}
TreeNode* insertIntoBST(TreeNode* root, int val) {
insert(root,val);
return root;
}
2.3 BST的删除
典例 BST的删除
老版思路:寻找前趋后继,然后用其代替。
高效思路:递归函数返回删除节点后的根节点。
root->val > key: 在左子树中删除,更新左指针;
root->val < key: 在右子树中删除,更新右指针;
root->val = = key :
左子树为空:直接用右子树代替;
右子树为空:直接用左子树代替;
左右都不空:寻找右子树的最小节点 min,将左子树挂到 min 上,然后用右子树替代。
左右都为空的情况?实际上,已经包含在了左/右为空的情况里面,若为空,则用 右/左替代,实际上就是用 null 替代,即为删除。
自底向上的后序思想。
// 返回删除了节点后的树根
TreeNode* deleteNode(TreeNode* root, int key) {
if(root ==nullptr) return nullptr;
if( root->val > key) {
root->left = deleteNode(root->left,key);
}else if(root->val < key) {
root->right = deleteNode(root->right,key);
}else {
if(root->left == nullptr) return root->right;
if(root->right == nullptr) return root->left;
TreeNode* cur = root->right;
while(cur->left != nullptr) cur = cur->left;
cur->left = root->left;
root = root->right;
}
return root;
}
3 总结
典例 将有序数组转换成AVL
贪心:取序列的中点作为根,划分左右区间,递归划分下去构造子树。
TreeNode* create(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 = create(nums,start,mid-1);
root->right = create(nums,mid+1,end);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
return create(nums,0,nums.size()-1);
}