验证二叉搜索树(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;
}

运行结果:

  

 

posted @ 2020-02-15 17:45  对影无眠  阅读(327)  评论(0编辑  收藏  举报