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?
OJ's Binary Tree Serialization:The serialization of a binary tree follows a level order traversal, where '#' signifies a path terminator where no node exists below.
Here's an example:
1 / \ 2 3 / 4 \ 5The above binary tree is serialized as"{1,2,3,#,#,4,#,#,5}"
.
大意就是恢复有两个位置交换了的二叉排序树。
思路大概就是用中序遍历,然后把顺序不对的两个数找出来。这里有两个问题。
1. 怎么找出两个被错误交换了的节点?
2. 题目要求最好用常量空间复杂度完成,但常见的中序遍历都是需要栈实现的,怎么做到?
问题1,只需要判断上一次访问的节点与当前节点的大小关系即可,第一个出现错误的是上一次访问节点(保证第一个出现的只记录一次),第二个出现错误的是当前节点。
问题2,就有点复杂了,我们先展示下用非递归和栈实现的代码:
1 /** 2 * Definition for binary tree 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 void recoverTree(TreeNode *root) { 13 if (NULL == root) 14 return; 15 stack<TreeNode*> nodes; 16 TreeNode *p = root; 17 TreeNode *pre = NULL, *first = NULL, *second = NULL; 18 while (p || !nodes.empty()) { 19 while (p) { 20 nodes.push(p); 21 p = p->left; 22 } 23 if (!nodes.empty()) { 24 p = nodes.top(); 25 nodes.pop(); 26 if (pre && pre->val > p->val) { 27 // second有可能是p 28 second = p; 29 if (!first) // first一定是pre 30 first = pre; 31 else // 当first非空,表明second一定是p 32 break; 33 } 34 pre = p; 35 p = p->right; 36 } 37 } 38 // 当所有节点遍历了,second就确定了 39 swap(first->val, second->val); 40 } 41 };
这里的判断条件需要认真考虑,pre->val > p->val的情况有可能出现1次(相邻时)或者2次,而first只取第一次出现这种情况时的pre,而second只取最后一次出现这种情况的p。
1 /** 2 * Definition for binary tree 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 void recoverTree(TreeNode *root) { 13 if (NULL == root) 14 return; 15 TreeNode *p = root; 16 TreeNode *pre = NULL, *first = NULL, *second = NULL; 17 while (p) { 18 if (p->left) { 19 TreeNode* tmp = p->left; 20 // 找出最右端右子节点不为空且不等于p的 21 while (tmp->right != NULL && tmp->right != p) 22 tmp = tmp->right; 23 if (tmp->right != p) { // 右子节点为空 24 tmp->right = p; 25 p = p->left; 26 } else { // 右子节点等于p 27 if (pre->val > p->val) { 28 if (!first) 29 first = pre; 30 second = p; 31 } 32 // 还原 33 tmp->right = NULL; 34 pre = p; 35 p = p->right; 36 } 37 } else { 38 if (pre && pre->val > p->val) { 39 if (!first) 40 first = pre; 41 second = p; 42 } 43 pre = p; 44 p = p->right; 45 } 46 } 47 swap(first->val, second->val); 48 } 49 };
对于这一方法,还原很重要,因为改变了原来的结构,因此也不能像之前说的方法那样可以提前break。