🧠
Optimal (Morris Inorder Traversal for O(1) Space)
💡 This approach uses Morris traversal to achieve inorder traversal without recursion or stack, reducing space to O(1). It is advanced but shows mastery of tree traversal techniques.
Intuition
Morris traversal temporarily modifies tree links to traverse inorder without extra space. Using the same violation detection logic, we find swapped nodes and fix them in-place.
Algorithm
- Initialize pointers: first, second, prev, and current node.
- While current is not null, if current has no left child, process current and move right.
- If current has left child, find predecessor (rightmost node in left subtree).
- If predecessor's right is null, set it to current and move current to left child.
- If predecessor's right is current, revert it to null, process current, and move right.
- During processing, detect violations as in previous approach.
- After traversal, swap values of first and second nodes.
💡 The complexity is in threading and unthreading the tree while detecting violations without recursion or stack.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def recoverTree(root):
first = second = prev = None
current = root
while current:
if not current.left:
if prev and prev.val > current.val:
if not first:
first = prev
second = current
else:
second = current
prev = current
current = current.right
else:
pred = current.left
while pred.right and pred.right != current:
pred = pred.right
if not pred.right:
pred.right = current
current = current.left
else:
pred.right = None
if prev and prev.val > current.val:
if not first:
first = prev
second = current
else:
second = current
prev = current
current = current.right
first.val, second.val = second.val, first.val
# Example usage:
# root = TreeNode(1, TreeNode(3, None, TreeNode(2)))
# recoverTree(root)
# Tree is fixed after recoverTree
Line Notes
current = rootStart traversal from root
if not current.left:If no left child, process current node directly
if prev and prev.val > current.val:Detect violation in inorder sequence
pred = current.leftFind predecessor in left subtree
while pred.right and pred.right != current:Find rightmost node in left subtree
pred.right = currentThread predecessor's right to current node
pred.right = NoneRemove temporary thread to restore tree
first.val, second.val = second.val, first.valSwap values of swapped nodes
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
public void recoverTree(TreeNode root) {
TreeNode first = null, second = null, prev = null, current = root;
while (current != null) {
if (current.left == null) {
if (prev != null && prev.val > current.val) {
if (first == null) {
first = prev;
second = current;
} else {
second = current;
}
}
prev = current;
current = current.right;
} else {
TreeNode pred = current.left;
while (pred.right != null && pred.right != current) {
pred = pred.right;
}
if (pred.right == null) {
pred.right = current;
current = current.left;
} else {
pred.right = null;
if (prev != null && prev.val > current.val) {
if (first == null) {
first = prev;
second = current;
} else {
second = current;
}
}
prev = current;
current = current.right;
}
}
}
int temp = first.val;
first.val = second.val;
second.val = temp;
}
public static void main(String[] args) {
TreeNode root = new TreeNode(1);
root.left = new TreeNode(3);
root.left.right = new TreeNode(2);
new Solution().recoverTree(root);
}
}
Line Notes
TreeNode first = null, second = null, prev = null, current = root;Initialize pointers for traversal and swapped nodes
if (current.left == null)If no left child, process current node
while (pred.right != null && pred.right != current)Find predecessor in left subtree
pred.right = current;Create temporary thread to current node
pred.right = null;Remove temporary thread to restore tree
int temp = first.val;Swap values of the two swapped nodes
while (current != null)Traverse until all nodes processed
#include <iostream>
using namespace std;
struct TreeNode {
int val;
TreeNode *left, *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
void recoverTree(TreeNode* root) {
TreeNode *first = nullptr, *second = nullptr, *prev = nullptr, *current = root;
while (current) {
if (!current->left) {
if (prev && prev->val > current->val) {
if (!first) {
first = prev;
second = current;
} else {
second = current;
}
}
prev = current;
current = current->right;
} else {
TreeNode* pred = current->left;
while (pred->right && pred->right != current) {
pred = pred->right;
}
if (!pred->right) {
pred->right = current;
current = current->left;
} else {
pred->right = nullptr;
if (prev && prev->val > current->val) {
if (!first) {
first = prev;
second = current;
} else {
second = current;
}
}
prev = current;
current = current->right;
}
}
}
swap(first->val, second->val);
}
};
// Example usage:
// int main() {
// TreeNode* root = new TreeNode(1);
// root->left = new TreeNode(3);
// root->left->right = new TreeNode(2);
// Solution().recoverTree(root);
// return 0;
// }
Line Notes
TreeNode *first = nullptr, *second = nullptr, *prev = nullptr, *current = root;Initialize pointers for traversal and swapped nodes
if (!current->left)If no left child, process current node
while (pred->right && pred->right != current)Find predecessor in left subtree
pred->right = current;Create temporary thread to current node
pred->right = nullptr;Remove temporary thread to restore tree
swap(first->val, second->val);Swap values of the two swapped nodes
while (current)Traverse until all nodes processed
function TreeNode(val, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
function recoverTree(root) {
let first = null, second = null, prev = null, current = root;
while (current) {
if (!current.left) {
if (prev && prev.val > current.val) {
if (!first) {
first = prev;
second = current;
} else {
second = current;
}
}
prev = current;
current = current.right;
} else {
let pred = current.left;
while (pred.right && pred.right !== current) {
pred = pred.right;
}
if (!pred.right) {
pred.right = current;
current = current.left;
} else {
pred.right = null;
if (prev && prev.val > current.val) {
if (!first) {
first = prev;
second = current;
} else {
second = current;
}
}
prev = current;
current = current.right;
}
}
}
let temp = first.val;
first.val = second.val;
second.val = temp;
}
// Example usage:
// let root = new TreeNode(1, new TreeNode(3, null, new TreeNode(2)));
// recoverTree(root);
// Tree is fixed after recoverTree
Line Notes
let first = null, second = null, prev = null, current = root;Initialize pointers for traversal and swapped nodes
if (!current.left)If no left child, process current node
while (pred.right && pred.right !== current)Find predecessor in left subtree
pred.right = current;Create temporary thread to current node
pred.right = null;Remove temporary thread to restore tree
let temp = first.val;Swap values of the two swapped nodes
while (current)Traverse until all nodes processed
Morris traversal visits each node at most twice, so O(n) time. Space is O(1) as no recursion or stack is used.
💡 For large trees, this approach saves memory by avoiding recursion stack, which is critical in memory-constrained environments.
Interview Verdict: Accepted and optimal with O(1) space
This is the most advanced solution, demonstrating mastery of tree traversal and in-place algorithms.