# 4.2. Minimal tree

> Given a sorted (increasing order) array with unique integer elements, create a binary search tree with minimal height.

From the README.md:

```bash
# This inequality must be true for all of a node's descendents, not just its immediate children. This is a binary search tree:

* 8
  * 4
    * 2
    * 6
  * 20
    * 10
    * 30
```

If I have an array [2, 4, 6, 8, 10, 20, 30], how do I put it in tree form?

* 2 on the left
* 4 as parent
* 6 as children of 4
* 8 as parent of 4 (but how do we know this?)
* 20 as child of 8
* 10 as child of 20
* 30 as child of 30

## Hints

> A minimal binary tree has about the same number of nodes on the left of each node as on the right. Focusing on just the root, how do we ensure that about the same number of nodes are on the left of the root as on the right?

Picking the middle number of the array? root = nums[len(nums)/2]

> Find an 'ideal' next element to add and repeatedly call `insertValue`. This will be inefficient as you would have to repeatedly traverse the tree, do recursion instead. Can you divide the problem into subproblems?

First create uppermost root, then recursively divide the array into 2, find the root of that (the element in the half of the half of the array), and add those roots as children of the uppermost root.

```java
import java.util.List;

class Node {
    public int value;
    public Node[] children;
}

class Tree {
    public Node root;
}

void createMinimalTree(List<Integer> nums) {

    if (nums.size() == 1) {
        return nums[0];
    }

    Node root = new Node();
    root.value = nums[int(nums.size()/2)]; // is supposed to do round down

    // https://stackoverflow.com/a/21587978/4569908
    int chunkSize = nums.size() % 2 == 0 ? nums.size() / 2 : (nums.size() / 2) + 1;
    List<Integer> firstHalf = nums.subList(0, chunkSize - 1); // -1 to exclude the root
    List<Integer> secondHalf = nums.subList(chunkSize + 1, nums.size());

    root.children.add(createMinimalTree(firstHalf));
    root.children.add(createMinimalTree(secondHalf));
}
```

Something like this should work:

* input = [2, 4, 6, 8, 10, 20, 30] root.value = 8, firstHalf = [2, 4, 6], secondHalf = [10, 20, 30]
  * input = [2, 4, 6] root.value = 4, firstHalf = [2], secondHalf = [6]
    * input = [2], return 2
  * 4 has 2 as child
    * input = [6], return 6
  * 4 has 2 and 6 as children
* 8 has 4 as child
  * etc.

> Imagine having a `createMinimalTree` method that returns a minimal tree for a given array, but doesn't operate on the root of the tree. Can you use this to operate on the root of the tree? Can you write the base case for the function?

Isn't that the function I've just done? Maybe the root is missing.

```java
void createMinimalTree(Node root, List<Integer> nums) {

    if (nums.size() == 1) {
        return nums[0];
    }

    root.value = nums.at(int(nums.size()/2)); // is supposed to do round down

    // https://stackoverflow.com/a/21587978/4569908
    int chunkSize = nums.size() % 2 == 0 ? nums.size() / 2 : (nums.size() / 2) + 1;
    List<Integer> firstHalf = nums.subList(0, chunkSize - 1); // -1 to exclude the root
    List<Integer> secondHalf = nums.subList(chunkSize + 1, nums.size());

    root.children.add(root.at(chunkSize), createMinimalTree(firstHalf));
    root.children.add(root.at(chunkSize), createMinimalTree(secondHalf));
}

Node superroot = new Node();
createMinimalTree(superroot, nums);
```

`.at()` is better than `[]` in arrays I think.

## Solution

We want the root to be the middle of the array. The middle of each subsection of the array becomes the root of the node. Left half of array is left subtree, and the right half of the array is the right subtree.

We could just use `root.insertNode(int v)` inserting the value `v` recursively, but we'd need to traverse the tree -> O(nlogn). Or we can cut out the extra traversals by recursively using the `createMinimalBST`. This is passed just a subsection of the array and returns the root of a minimal tree for that array. Algorithm:

1. Insert into the tree the middle element of the array
2. Insert (into left subtree) the left subarray elements
3. Insert (into right subtree) the right subarray elements
4. Recurse

```java
TreeNode createMinimalBST(int[] array) {
    return createMinimalBST(array, 0, array.length - 1)
}

TreeNode createMinimalBST(int arr[], int start, int end) {
    if (end < start) return;

    int mid = (start + end) / 2;
    TreeNode n = new TreeNode(arr[mid]);
    n.left = createMinimalBST(arr, start,  mid - 1);
    n.right = createMinimalBST(arr, mid + 1, end);
    return n;
}
```
