Skip to content

Instantly share code, notes, and snippets.

@akshay3030
Forked from kean/CtCI-6h-problem-4.9.markdown
Last active September 25, 2019 05:35
Show Gist options
  • Select an option

  • Save akshay3030/65d8c4ad57b89a4827241283cb372343 to your computer and use it in GitHub Desktop.

Select an option

Save akshay3030/65d8c4ad57b89a4827241283cb372343 to your computer and use it in GitHub Desktop.
CtCI 6h Edition, Problem 4.9: BST Sequences.

Problem 4.9. BST Sequences: A binary search tree was created by traversing through an array from left to right and inserting each element. Given a binary search tree with distinct elements, print all possible arrays that could have led to this tree.

Solution.

Let's start with an example.

    4
   / \
  2   5 
 / \   \
1   3   6

To construct this tree we must insert the node 4 first. This node is always going to be the first element in each of the possible solution. Lets remove this node from the tree.

  2    5    
 / \    \
1   3    6

To continue construcing the tree from the example we now have a choice of eather inserting 2 or 5. Notice that both are the roots of the respective subtrees. Lets start with node 2 and remove it from the tree.

1   3   5
         \
          6

We are left with 3 subtrees. We now have a choice of removing either 1, 3 or 5.

You can cleary see that there is an inductive step which we can use to implement our solution:

start with a root of the tree (the only valid choice)

for each of the current valid choices:
- remove one of the roots (valid choices), add its children to the set of choices
- recursively find all possible solutions for the new set of choices
- append the root to the head of each of those solutions

the recursion ends when there are no remaining nodes (choices) left

Implementation.

Here's an actual code written in Swift. It uses arrays, but it might make sense to use lists instead. The key to implementing the algorithm is to keep the array of all choices after removing the node from the tree.

public class Node<T> {
    public var value: T
    public var left: Node<T>?
    public var right: Node<T>?

    public var children: [Node<T>] {
        var output = [Node<T>]()
        if let left = left { output.append(left) }
        if let right = right { output.append(right) }
        return output
    }
    
    public init(_ value: T) {
        self.value = value
    }
}

func bstSequences<T>(_ tree: Node<T>) -> [[T]] {
    return bstSequences([tree])
}

func bstSequences<T>(_ roots: [Node<T>]) -> [[T]] {
    var output = [[T]]()
    
    for i in roots.indices {
        var choices = roots
        let root = choices.remove(at: i)
        choices.append(contentsOf: root.children)
        
        if choices.count > 0 {
            for s in bstSequences(choices) {
                output.append([root.value] + s)
                // print(output)
            }
        } else {
            output.append([root.value]) // end recursion
            // print(output)
        }
    }
    
    return output
}

func sortedArrayToBST<T>(_ nums: [T]) -> Node<T>? {
    if nums.count == 0 {
        return nil
    }
    
    let mid = nums[nums.count/2]
    
    let tree = Node(mid)
    
    let leftnums = Array(nums[0..<nums.count/2])
    let rightnums = Array(nums[nums.count/2 + 1..<nums.count])
    
    tree.left = sortedArrayToBST(leftnums)
    tree.right = sortedArrayToBST(rightnums)
    
    return tree
}

//Testing
for s in bstSequences(sortedArrayToBST([1, 2, 3, 4, 5, 6])!) {
    print(s)
}

// var s = bstSequences(sortedArrayToBST([1, 2, 3, 4, 5, 6])!)
// print(s)

// var N1 = Node(1)
// print(N1.value)

Testing the solution:

for s in bstSequences(sortedArrayToBST([1, 2, 3, 4, 5, 6])!) {
    print(s)
}

Output:

[4, 2, 6, 1, 3, 5]
[4, 2, 6, 1, 5, 3]
[4, 2, 6, 3, 1, 5]
[4, 2, 6, 3, 5, 1]
[4, 2, 6, 5, 1, 3]
[4, 2, 6, 5, 3, 1]
[4, 2, 1, 6, 3, 5]
[4, 2, 1, 6, 5, 3]
[4, 2, 1, 3, 6, 5]
[4, 2, 3, 6, 1, 5]
[4, 2, 3, 6, 5, 1]
[4, 2, 3, 1, 6, 5]
[4, 6, 2, 5, 1, 3]
[4, 6, 2, 5, 3, 1]
[4, 6, 2, 1, 5, 3]
[4, 6, 2, 1, 3, 5]
[4, 6, 2, 3, 5, 1]
[4, 6, 2, 3, 1, 5]
[4, 6, 5, 2, 1, 3]
[4, 6, 5, 2, 3, 1]

Here's a tree implementation used in the solution:

public class Node<T> {
    public var value: T
    public var left: Node<T>?
    public var right: Node<T>?

    public var children: [Node<T>] {
        var output = [Node<T>]()
        if let left = left { output.append(left) }
        if let right = right { output.append(right) }
        return output
    }
    
    public init(_ value: T) {
        self.value = value
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment