LeetCode 99. Recover Binary Search Tree

来源:互联网 发布:ubuntu 统计目录大小 编辑:程序博客网 时间:2024/05/16 12:18

1. 题目描述

Two elements of a binary search tree (BST) are swapped by mistake.
Recover the tree without changing its structure.
Note:
A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?

2. 解题思路

拿到这道题目, 经过分析, 我们知道如果这是一个数组的问题, 有两个值不满足数组递增排序, 只需要找到这两个位置, 交换他们的值就可以了。 但是这是一颗树, 不过没关系, 我们可以通过中序遍历获取他的这个递增数组哦。
这里写图片描述

3. code

class Solution {public:    void recoverTree(TreeNode* root) {        bool ret = search(root);        if (!ret)            swap(myfirst->val, mysecond->val);    }private:    bool search(TreeNode * root){        if (!root) return false;        bool ret = search(root->left);        if (ret) return true;        if (last && root->val < last->val){            if (first){                myfirst = last;                mysecond = root;                first = false;            }                           else{                swap(myfirst->val, root->val);                return true;            }        }               last = root;        return search(root->right);    }    TreeNode * last = nullptr;    bool first = true;    TreeNode * myfirst = nullptr;    TreeNode * mysecond = nullptr;};

4. 大神解法

4.1 inorder traversal 一样的处理思想

/*This question appeared difficult to me but it is really just a simple in-order traversal! I got really frustrated when other people are showing off Morris Traversal which is totally not necessary here.Let's start by writing the in order traversal:private void traverse (TreeNode root) {   if (root == null)      return;   traverse(root.left);   // Do some business   traverse(root.right);}So when we need to print the node values in order, we insert System.out.println(root.val) in the place of "Do some business".What is the business we are doing here? We need to find the first and second elements that are not in order right?How do we find these two elements? For example, we have the following tree that is printed as in order traversal:6, 3, 4, 5, 2We compare each node with its next one and we can find out that 6 is the first element to swap because 6 > 3 and 2 is the second element to swap because 2 < 5.Really, what we are comparing is the current node and its previous node in the "in order traversal".Let us define three variables, firstElement, secondElement, and prevElement. Now we just need to build the "do some business" logic as finding the two elements. See the code below:*/public class Solution {    TreeNode firstElement = null;    TreeNode secondElement = null;    // The reason for this initialization is to avoid null pointer exception in the first comparison when prevElement has not been initialized    TreeNode prevElement = new TreeNode(Integer.MIN_VALUE);    public void recoverTree(TreeNode root) {        // In order traversal to find the two elements        traverse(root);        // Swap the values of the two nodes        int temp = firstElement.val;        firstElement.val = secondElement.val;        secondElement.val = temp;    }    private void traverse(TreeNode root) {        if (root == null)            return;        traverse(root.left);        // Start of "do some business",         // If first element has not been found, assign it to prevElement (refer to 6 in the example above)        if (firstElement == null && prevElement.val >= root.val) {            firstElement = prevElement;        }        // If first element is found, assign the second element to the root (refer to 2 in the example above)        if (firstElement != null && prevElement.val >= root.val) {            secondElement = root;        }                prevElement = root;        // End of "do some business"        traverse(root.right);}

4.2 morris

由于对morris 还不够了解, 先mark 一下

/*To understand this, you need to first understand Morris Traversal or Morris Threading Traversal. It take use of leaf nodes' right/left pointer to achieve O(1) space Traversal on a Binary Tree. Below is a standard Inorder Morris Traversal, referred from http://www.cnblogs.com/AnnieKim/archive/2013/06/15/morristraversal.html (a Chinese Blog, while the graphs are great for illustration)public void morrisTraversal(TreeNode root){        TreeNode temp = null;        while(root!=null){            if(root.left!=null){                // connect threading for root                temp = root.left;                while(temp.right!=null && temp.right != root)                    temp = temp.right;                // the threading already exists                if(temp.right!=null){                    temp.right = null;                    System.out.println(root.val);                    root = root.right;                }else{                    // construct the threading                    temp.right = root;                    root = root.left;                }            }else{                System.out.println(root.val);                root = root.right;            }        }    }In the above code, System.out.println(root.val);appear twice, which functions as outputing the Node in ascending order (BST). Since these places are in order, replace them with    if(pre!=null && pre.val > root.val){        if(first==null){first = pre;second = root;}        else{second = root;}  }pre = root;each time, the pre node and root are in order as System.out.println(root.val); outputs them in order.Then, come to how to specify the first wrong node and second wrong node.When they are not consecutive, the first time we meet pre.val > root.val ensure us the first node is the pre node, since root should be traversal ahead of pre, pre should be at least at small as root. The second time we meet pre.val > root.val ensure us the second node is the root node, since we are now looking for a node to replace with out first node, which is found before.When they are consecutive, which means the case pre.val > cur.val will appear only once. We need to take case this case without destroy the previous analysis. So the first node will still be pre, and the second will be just set to root. Once we meet this case again, the first node will not be affected.Below is the updated version on Morris Traversal.*/public void recoverTree(TreeNode root) {        TreeNode pre = null;        TreeNode first = null, second = null;        // Morris Traversal        TreeNode temp = null;        while(root!=null){            if(root.left!=null){                // connect threading for root                temp = root.left;                while(temp.right!=null && temp.right != root)                    temp = temp.right;                // the threading already exists                if(temp.right!=null){                    if(pre!=null && pre.val > root.val){                        if(first==null){first = pre;second = root;}                        else{second = root;}                    }                    pre = root;                    temp.right = null;                    root = root.right;                }else{                    // construct the threading                    temp.right = root;                    root = root.left;                }            }else{                if(pre!=null && pre.val > root.val){                    if(first==null){first = pre;second = root;}                    else{second = root;}                }                pre = root;                root = root.right;            }        }        // swap two node values;        if(first!= null && second != null){            int t = first.val;            first.val = second.val;            second.val = t;        }    }
0 0