交换两个元素修正 BST
题目中说的很直观的 的方法, 想到了一个。
BST 的中序遍历结果是递增的序列, 根据这个可以用两个向量分别保存中序遍历的节点,和节点的值,对值排序后赋给结点
class Solution
{
public:
void inOrder(TreeNode* root, vector& Tnode, vector& Tval)
{
if (!root) return;
inOrder(root->left, Tnode, Tval);
Tnode.push_back(root);
Tval.push_back(root->val);
inOrder(root->right, Tnode, Tval);
}
void recoverTree(TreeNode* root)
{
vector Tnode;
vector Tval;
inOrder(root, Tnode, Tval);
sort(Tval.begin(), Tval.end());
for (int i = 0; i < Tnode.size(); ++i)
{
Tnode[i]->val = Tval[i];
}
}
};
因为只有两个节点错误,可以使用指针来省略两个vector, 不过一般的中序遍历(包括递归和使用栈的迭代法)本身需要的栈空间, 仍然不满足要求。
Mirrors 遍历
如果需要 的空间复杂度, 可以使用 Mirrors Traversal. 要理解这种方法, 可以通过线索二叉树(threaded binary tree)
线索二叉树
保存了每个节点前驱和后继的二叉树.
前驱: 某种遍历次序下该节点之前的节点
后继: 某种遍历次序下该节点之后的节点
对线索二叉树的遍历只需要从最先的节点一路访问后继就可以,不需要额外空间
Mirrors 遍历
通过暂时修改左右孩子指针,不需要新的指针域
具体步骤, 以中序遍历为例
- 初始化 cur 为 root
- 如果 cur 没有前驱(没有左孩子),访问当前节点, cur=cur->right
- 如果 cur 有左孩子
- 如果先左孩子,再向右走到空,将最右的叶子节点右孩子指向 cur (暂时修改了树的结构), cur=cur->left;
- 如果先左孩子,再向右走能回到 cur,将 cur 前驱的右孩子重新设为空(恢复树的结构)。输出当前节点。当前节点更新为当前节点的右孩子
- 如果 cur 不为空, 重复 2,3