Solution


Approach 1: Sort an Almost Sorted Array Where Two Elements Are Swapped

Intuition

Let's start from straightforward but not optimal solution
with a linear time and space complexity.
This solution serves to identify and discuss all subproblems.

It's known that inorder traversal of BST is an array sorted in
the ascending order
.
Here is how one could compute an inorder traversal

Here two nodes are swapped, and hence inorder traversal is
an almost sorted array where only two elements are swapped.
To identify two swapped elements in a sorted array is
a classical problem that could be solved in linear time.
Here is a solution code

When swapped nodes are known, one could traverse the tree
again and swap their values.

Algorithm

Here is the algorithm:

  1. Construct inorder traversal of the tree.
    It should be an almost sorted list where only two elements are swapped.

  2. Identify two swapped elements x and y in an almost sorted array
    in linear time.

  3. Traverse the tree again. Change value x to y and value y to x.

Implementation

Complexity Analysis



What Is Coming Next

In approach 1 we discussed three easy subproblems of this hard problem:

  1. Construct inorder traversal.

  2. Find swapped elements in
    an almost sorted array where only two elements are swapped.

  3. Swap values of two nodes.

Now we will discuss three more approaches, and basically they are
all the same :

The difference in-between the following approaches is in a chosen
method to implement inorder traversal :

Iterative and recursive approaches here do less than one pass,
and they both need up to O(H)\mathcal{O}(H) space to keep stack,
where H is a tree height.

Morris approach is two pass approach, but it's a constant-space one.




Approach 2: Iterative Inorder Traversal

Intuition

Here we construct inorder traversal by iterations
and identify swapped nodes at the same time, in one pass.

Iterative inorder traversal is simple:
go left as far as you can, then one step right. Repeat till
the end of nodes in the tree.

To identify swapped nodes,
track the last node pred in the inorder traversal (i.e. the
predecessor of the current node)
and compare it with current node value.
If the current node value is smaller than its predecessor pred value,
the swapped node is here.

There are only two swapped nodes here, and hence one could break after
having the second node identified.

Doing so, one could get directly nodes (and not only their values),
and hence swap node values in O(1)\mathcal{O}(1) time, drastically
reducing the time needed for step 3.

Current
1 / 9

Implementation

Don't use Stack in Java, use ArrayDeque instead.

Complexity Analysis



Approach 3: Recursive Inorder Traversal

Iterative approach 2 could be converted into recursive one.

Recursive inorder traversal is extremely simple:
follow Left->Node->Right direction, i.e. do the recursive call
for the left child, then do all the business with the node
(= if the node is the swapped one or not), and
then do the recursive call for the right child.

On the following figure the nodes are numerated in the order you visit them,
please follow 1-2-3-4-5 to compare different DFS strategies.

Implementation

Complexity Analysis



Approach 4: Morris Inorder Traversal

We discussed already iterative and recursive inorder traversals,
which both have great time complexity though use up to
O(N)\mathcal{O}(N) to keep stack.
We could trade in performance to save space.

The idea of Morris inorder traversal is simple:
to use no space but to traverse the tree.

How that could be even possible? At each node one has to decide where to go:
left or right, traverse left subtree or traverse right subtree.
How one could know that the left subtree is already done if no
additional memory is allowed?

The idea of Morris
algorithm is to set the temporary link between the node and its
predecessor:
predecessor.right = root.
So one starts from the node, computes its predecessor and
verifies if the link is present.

There is one small issue to deal with : what if there is no
left child, i.e. there is no left subtree?
Then go straightforward to the right subtree.

Current
1 / 11

Implementation

Complexity Analysis