验证二叉搜索树(lc98)、恢复二叉搜索树(lc99)
二叉搜索树
二叉搜索树是这样的二叉树,树中所有结点满足:左子树所有结点值小于根结点,右子树所有结点值大于根结点。
验证方法
首先想到的是使用递归方法,如果满足前驱结点 < 根结点 < 后继结点,那么继续向下分别对左右子树进行递归,直到有不满足的情况出现,则返回false。还有一种递归想法(参考题解)是为每个子树设置(low, upper),判断根节点值root是否在区间内,然后对左右子树递归判断,左子树区间设置为(low,root-1),右子树为(root+1,upper),并且该方法可以很容易转化为栈实现,具体参考https://leetcode-cn.com/problems/validate-binary-search-tree/solution/yan-zheng-er-cha-sou-suo-shu-by-leetcode/。
下面是第一种递归算法实现
bool isValidBST(TreeNode* root) {
if(root == NULL) return true;
TreeNode* pre = root->left;
TreeNode* follow = root->right;
if(pre == NULL && follow == NULL)
return true;
if(pre == NULL){
while(follow->left) follow = follow->left;
if(isValidBST(root->right) && root->val < follow->val)
return true;
return false;
}
if(follow == NULL){
while(pre->right) pre = pre->right;
if(isValidBST(root->left) && root->val > pre->val)
return true;
return false;
}
while(follow->left) follow = follow->left;
while(pre->right) pre = pre->right;
if(isValidBST(root->left) && isValidBST(root->right) && root->val < follow->val && root->val > pre->val)
return true;
return false;
}
还有一种常见的方法是对二叉树进行中序遍历,根据搜索树的性质可知,中序遍历的序列是递增的。下面使用栈方法进行中序遍历验证二叉搜索树(也可使用递归遍历或莫里斯遍历)。
bool isValidBST(TreeNode* root) {
vector<TreeNode*> stk;
TreeNode* cur = root;
long before = (long)INT_MIN - 1;
while(cur != NULL || stk.size() != 0){
while(cur != NULL){
stk.push_back(cur);
cur = cur->left;
}
cur = stk.back();
stk.pop_back();
if(cur->val <= before) return false;
before = cur->val;
cur = cur->right;
}
return true;
}
恢复二叉搜索树
如果二叉搜索树中有两个节点互换了位置,请恢复它。
思路:二叉搜索树的中序遍历会得到递增序列,因此在中序遍历的过程中识别非递增的节点,则可以找到那两个节点的位置(即线性时间寻找递增序列中进行交换的两个值),找到后停止遍历,进行恢复。
下面使用两种中序遍历方式进行恢复,分别是递归实现和栈迭代实现。
递归方法
TreeNode* pre = NULL;
TreeNode* first = NULL;
TreeNode* second = NULL;
void recoverTree(TreeNode* root){
bool isok = false;
recoverTree(root, isok);
int t = first->val;
first->val = second->val;
second->val = t;
return;
}
void recoverTree(TreeNode* root, bool& isok) {
if(!isok && root){
recoverTree(root->left,isok);
if(isok) return;
if(pre && root->val < pre->val){
second = root;
if(first) {
isok = true;
return;
}
first = pre;
}
pre = root;
recoverTree(root->right,isok);
}
return;
}
运行结果如图:
栈方法
void recoverTree(TreeNode* root) { TreeNode* pre = NULL; TreeNode *first = NULL; TreeNode *second = NULL; stack<TreeNode*> stk; while(root || stk.size()){ while(root){ stk.push(root); root = root->left; } root = stk.top(); stk.pop(); if(pre && root->val < pre->val){ second = root; if(first) break; first = pre; } pre = root; root = root->right; } int t = first->val; first->val = second->val; second->val = t; return; }
运行结果: