Question:
You have a binary tree. But only two of its elements have been swapped. This makes it a faulty binary tree. The challenge is to swap those two elements. And fix the tree.
Solution
I knew I had to traverse it. But then what?
With a little help from reading online, I realized I should traverse it, and store the values into an array. Then you just loop the array and find the bad indexes.
Here’s the tricky part:
Suppose your array is something like:
[1, 2, 4, 3, 6, 7, 8]
You loop and find out 4 is in a bad spot. You swap it with 3. And your tree is fixed.
However if your array ends up like this:
[1, 2, 8, 4, 6, 7, 3]
You loop and find out 8, is in a bad spot. You swap it with 4 and up with:
[1, 2, 4, 8, 6, 7, 3]
but that’s still incorrect.
So once you have the array built, what you need to do is:
- Find the first item that not in its place. Let’s name this
f(for first). - Continue comparing every two consecutive pair to find the last item that’s not in its place. Let’s name this
s(for second). As soon as you find the 2nd item, then you can stop searching. - Swap those two items.
To show you step two visually:
[1, 2, 8, 4, 6, 7, 3]
↑ ↑
❗️ ❗️
f s
[1, 2, 8, 4, 6, 7, 3]
↑__↑ ↑__↑
first-pair second-pair
f ← → s
Perform swap between `f` and `s`:
[1, 2, 3, 4, 6, 7, 8]
The heart of all the code would be:
var fBadVal: Int?
var sBadVal: Int?
var didFindFirstNodeThatNeedsSwapping = false
for i in 0..<tree.count {
if let next = tree[safe:i + 1], next.val < tree[i].val{
if didFindFirstNodeThatNeedsSwapping == false {
fBadVal = tree[i].val
didFindFirstNodeThatNeedsSwapping = true
}
sBadVal = tree[i + 1].val
}
}
Setup of bad Binary tree:
class TreeNode {
var val: Int
var left: TreeNode?
var right: TreeNode?
init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) {
self.val = val
self.left = left
self.right = right
}
}
var one = TreeNode(1, nil, nil)
var eight = TreeNode(8, nil, nil) // bad position
var six = TreeNode(6, nil, nil)
var three = TreeNode(3, nil, nil) // bad position
var two = TreeNode(2,one, eight)
var seven = TreeNode(7, six, three)
// root node
var four = TreeNode(4, two, seven)
1, 2, 8, 4, 7, 6 , 3
4
/ \
2 7
/ \ / \
1 8 6 3
Actual code:
class TreeFixer {
var tree: [TreeNode] = []
func recoverTree(_ root: TreeNode?) {
// traverse the tree
inOrder(root) { node in
node.map {tree.append($0)}
}
print(tree.map {$0.val})
// find the elements where they're not matching...
var fBadVal: Int?
var sBadVal: Int?
var didFindFirstNodeThatNeedsSwapping = false
for i in 0..<tree.count {
if let next = tree[safe:i + 1], next.val < tree[i].val{
if didFindFirstNodeThatNeedsSwapping == false {
fBadVal = tree[i].val
didFindFirstNodeThatNeedsSwapping = true
}
sBadVal = tree[i + 1].val
}
}
print(fBadVal, sBadVal)
// traverse again & swap elements
inOrder(root) { node in
node.map { node in
if node.val == fBadVal {
node.val = sBadVal!
} else if node.val == sBadVal {
node.val = fBadVal!
}
}
}
// print new tree, so we can validate our work...
print("SORTED TREE: InOrderTraversal")
inOrder(root) { node in
print(node?.val)
}
}
// Traverse tree and return a block handler for each node.
func inOrder(_ root: TreeNode?, nodeHandler: (TreeNode?) -> ()) {
if let left = root?.left {
inOrder(left) { node in
nodeHandler(node)
}
}
nodeHandler(root)
if let right = root?.right {
inOrder(right) { node in
nodeHandler(node)
}
}
}
}
extension Array {
public subscript(safe index: Int) -> Element? {
guard index >= 0, index < endIndex else {
return nil
}
return self[index]
}
}
let fixer = TreeFixer()
fixer.recoverTree(four)
Time Complexity
- Traversing is
O(n). - Appending to the array is
O(1). - Traversing the array is
O(n). - swapping in the tree is
O(n).
Given that they’re not nested to total Time complexity is O(n)
Space Complexity
O(n) because you need an array.
Summary:
- Often translating a tree into an array can be helpful.
- Using an
inOrdermethod that takes a handler block can be helpful. - Using a safe subscript for the array…something that Swift doesn’t have can be helpful.
- main trick was to continuously look for 2nd index.