11

I got a problem during one of my mock interview where I had to find how long will a binary tree completely burn down after one given node is already on fire.

"A binary tree is started burning from a leaf node. What is the time(1second to burn from node to node) it takes to entire tree get burned? The fire will spread to all the paths from a node."

Say you have a tree like this, where N is the node that is on fire. This is happening in the first second, where seconds is s, so in the zeroth s:

           1
       /       \
      1          1
    /  \          \
   1    1          1
      /   \         \
     1     N         1
                      \
                       1

After one second has passed, the tree will be updated with more burned nodes. An example of the next second (s + 1) will be like this:

           1
       /       \
      1          1
    /  \          \
   1    N          1
      /   \         \
     1     N         1
                      \
                       1

An example of the next second (s + 2) will be like this:

           1
       /       \
      N          1
    /  \          \
   1    N          1
      /   \         \
     N     N         1
                      \
                       1  

Now at the third second (s + 3) will be like this:

           N
       /       \
      N          1
    /  \          \
   N    N          1
      /   \         \
     N     N         1
                      \
                       1

With the same pattern, the tree will be burned in (s + 7)

           N
       /       \
      N          N
    /  \          \
   N    N          N
      /   \         \
     N     N         N
                      \
                       N

After understanding a little bit, I did a small research in figuring out how to do it. I found this cool article and followed it up and implement the idea behind.

My approach was to find the diameter, along with the height of the tree to look for the furthest node to node. However, when I implemented my functions, I'm only getting the result of the starting node to the end of the given node without checking the previous parent nodes. Here is my implementation in Python 3:

# Tree class
class Node:
    def __init__(self, key):
        self.left = None
        self.right = None
        self.value = key

# Maximum height of a tree
def maxHeight(root):
    if root is None:
        return 0
    else:
        return 1 + max(maxHeight(root.left), maxHeight(root.right))

# Diameter of the tree
def maxDiameter(root):
    how_long = 0
    if root is None:
        return 0
    else:
        root_diameter = maxHeight(root.left) + maxHeight(root.right)

        left_diameter = maxDiameter(root.left)
        right_diameter = maxDiameter(root.right)
        how_long = max(max(left_diameter, right_diameter), root_diameter)
        return how_long

# Sample code
root = Node(1)
root.left = Node(1)
root.right = Node(1)
root.left.left = Node(1)
root.left.right = Node(1)
root.left.right.left = Node(1)
root.left.right.right = Node(1)
root.right.right = Node(1)
root.right.right.right = Node(1)
root.right.right.right.right = Node(1)
print ("Starting from the given node, it will take %ds to burn the whole tree" % (maxDiameter(root.left.right)))

The expected output for this example should be 6s (starting from the 0s with the given node). But again, I'm not getting the full scope of the tree. From my own understanding, it has to work with all cases. So, what search would be helpful here, DFS or BFS? I think having this in mind will guide me towards my solution, but again. Any feedback is appreciated :)

Zeid Tisnes
  • 374
  • 4
  • 17
  • 2
    The question says the fire starts in a leaf node, but your example starts in a node that isn't a leaf. – m69 ''snarky and unwelcoming'' Oct 12 '18 at 22:38
  • also, what's with the last second? you burn 3 nodes that are not connected to the closest source – Yuca Oct 12 '18 at 22:41
  • I would guess the longest would be weight to root + the weight of the leaf with the highest weight to a common ancestor and the time in seconds would be those added together. Every other node would be reached in less time. – Sylwester Oct 12 '18 at 22:42
  • You are right @m69 – Zeid Tisnes Oct 12 '18 at 22:45
  • Fixing my example @Yuca after I made few changes. – Zeid Tisnes Oct 12 '18 at 22:47
  • Traverse the tree from root to burning leaf and then, while going back up, for each node, measure the height of the other sub-tree attached to that node (which doesn't containt he burning leaf). The maximum sum of height below a node plus distance from burning leaf is your answer. – m69 ''snarky and unwelcoming'' Oct 12 '18 at 22:51
  • A tree is just a graph, so using Dijkstra's algorithm with weighs all 1 should give you the time in seconds for each node; take the maximum? – Neil Oct 12 '18 at 22:55
  • I set all my values of the node into 1, which makes much more sense if I ever get this interview again @Neil Edelman. – Zeid Tisnes Oct 12 '18 at 22:56
  • I did traverse, but from one point to another I wasn't getting my expected results @m69 – Zeid Tisnes Oct 12 '18 at 22:57
  • The edge weights all 1, that is. I don't think any specifically tree algorithm is going to be appropriate because one is not guaranteed anything about the balance of the tree. – Neil Oct 12 '18 at 23:15
  • For this example, we don't really have to worry about balanced trees @NeilEdelman – Zeid Tisnes Oct 12 '18 at 23:32
  • @ZeidTisnes just that the path to the farthest distance may not go though the root, which, I have an intuition, it would if it was balanced? – Neil Oct 13 '18 at 22:06

9 Answers9

4

It occurs to me that you need the following:

  1. Whether the starting node is left or right of the root.
  2. The depth of the starting node (call it dStart).
  3. The depth of the node furthest from the root on the starting node's branch (i.e. left or right of the root). We'll call that dSameSide
  4. Depth of the lowest common ancestor of the starting node and the node identified in #3. (call it dCommonAncestor)
  5. Depth of the lowest node on the opposite side of the tree, dOppositeSide.

You can obtain all that information from a single inorder traversal of the tree.

The number of steps it takes to get from the starting node to the deepest node on that side of the tree is (dSameSide - dCommonAncestor) + (dStart - dCommonAncestor).

The number of steps it takes to get from the starting node to the deepest node on the opposite side is (dStart + dOppositeSide).

And the number of steps it takes to burn the entire tree is the maximum of those two.

I'll leave the implementation to you. You'll probably find How to find the lowest common ancestor of two nodes in any binary tree? helpful.

Jim Mischel
  • 122,159
  • 16
  • 161
  • 305
  • As you'll see, Dukeling's Python code and my JS code snippet do one complete traversal (recursive BFS). – m69 ''snarky and unwelcoming'' Oct 13 '18 at 06:08
  • @m69 It looks like you and Dukeling are doing depth-first rather than breadth-first traversals. In any case, my answer explains at a high level what I think is the simplest approach. Thinking through a problem this way often makes writing the code almost an afterthought. – Jim Mischel Oct 13 '18 at 06:26
  • 1
    Sorry, meant to type DFS. – m69 ''snarky and unwelcoming'' Oct 13 '18 at 06:28
  • Yeah, after discussing with some of my colleagues, apparently they were referring about the common ancestors and I was looking at it. I'm trying to understand it how it reads the previous parent/ancestor value. The link that you gave me it is pretty useful. Thank you @JimMischel :) – Zeid Tisnes Oct 15 '18 at 02:16
2

This can be solved using a recursive function which returns the length of the path from the current node down to the starting node (or just the longest path to any leaf if the starting node isn't below it).

We can also have it return the longest path so far from the starting node, if found, which is simply the sum of the function called on both the left and right children (plus one, for the current node).

This is similar to the solution described by m69.

This runs in O(n) time since the function runs in constant time (if you exclude the recursive calls), and the function gets called at most three times for each node (for the node itself and for its left and right children, in the case of leaf nodes).

This will use O(height) space, since we're not storing anything apart from the function calls with their variables, and the maximum number of those we can have in memory at any given time is equal to the recursion depth (i.e. the height of the tree).

class Node:
    def __init__(self, key):
        self.left = None
        self.right = None
        self.value = key

# returns a tuple (max = the longest path so far, dist = current path)
def _recurse(node, start):
    if node is None:
        return (None, 0)
    else:
        max_left, dist_left = _recurse(node.left, start)
        max_right, dist_right = _recurse(node.right, start)
        # this node is the starting node
        if node == start:
            return (0, 0)
        # the starting node is in left or right
        elif max_right is not None or max_left is not None:
            return (dist_right + dist_left + 1,
                    (dist_left if max_right is None else dist_right) + 1)
        # we haven't seen the starting node
        else:
            return (None, max(dist_left, dist_right) + 1)

def time_to_burn(root, start):
    return _recurse(root, start)[0]

Test:

root = Node(1)
root.left = Node(1)
root.right = Node(1)
root.left.left = Node(1)
root.left.right = Node(1)
root.left.right.left = Node(1)
root.left.right.right = Node(1)
root.right.right = Node(1)
root.right.right.right = Node(1)
root.right.right.right.right = Node(1)

>>> time_to_burn(root, root.left.right.right)
7

Solution which works with non-leaf starting nodes

The basic idea is to have 3 return values for each node:

  • max, which is the longest path from the starting node gotten so far (or None if we haven't seen the starting node yet).
  • above, which is the number of nodes above the starting node (or None if we haven't seen the starting node yet).
  • below, which is the longest path below the starting node (or just the longest path from the current node if we haven't seen the starting node yet).

Calculating above and below from the child subtrees is fairly straight-forward - see the code for details.

We can define the longest path max from the current node as the maximum of:

  • The longest path going downwards from the starting node (which is just below)
  • and the longest path which includes the current node, which will be the distance from the current node to the starting node plus the longest path in the subtree without the starting node (plus one).

Code: (replacing the _recurse function above)

# returns a tuple (max, above, below)
def _recurse(node, start):
    if node is None:
        return (None, None, 0)
    else:
        max_left, above_left, below_left = _recurse(node.left, start)
        max_right, above_right, below_right = _recurse(node.right, start)
        # this node is the starting node
        if node == start:
            below = max(below_left, below_right)
            return (below, 0, below)
        # the starting node is in left or right
        elif above_right is not None or above_left is not None:
            return (max((0 if above_right is None else above_right) + below_left,
                        (0 if above_left is None else above_left) + below_right) + 1,
                    (above_right if above_left is None else above_left) + 1,
                    below_right if above_left is None else below_left)
        # we haven't seen the starting node
        else:
            return (None, None, max(below_left, below_right) + 1)

>>> time_to_burn(root, root.left.right)
6
Bernhard Barker
  • 50,899
  • 13
  • 85
  • 122
  • As far as I'm reading your code, it looks that this runs in an O(n) or O(logn)? Where n is the node located right? How can you explain your time and space complexity? Because you are checking one by one with the recursive calls correct? – Zeid Tisnes Oct 15 '18 at 02:43
  • What would be the best way to optimize this if the interviewer would have ask? I was thinking in a hash table with all the nodes and store all possible combinations like this example: techieme.in/tree-diameter (second picture) @Dukeling – Zeid Tisnes Oct 18 '18 at 01:45
  • 1
    @ZeidTisnes There's no way to (significantly) improve on this - it's already asymptotically optimal - you can't do better than visiting every node once. Unless you want to run many queries on the same tree, with different nodes as the starting point, but that's a different question entirely. – Bernhard Barker Oct 18 '18 at 17:03
1

Take the example below; first, traverse from the root to the leaf on fire (F):

     N
    / \
   N   N
  / \   \
 N   N   N
    / \   \
   N   F   N
  / \       \
 N   N       N
      \
       N

Then, move up to its parent node, and take the sum of the distance to the burning leaf (1) and the height of the left sub-tree (3), which is 4:

     N
    / \
   N   N
  / \   \
 N   4   N
    / \   \
   3   1   N
  / \       \
 N   2       N
      \
       1

So 4 is the current maximum. Now, move up to the parent node, and take the sum of the distance to the burning leaf (2) and the depth of the left sub-tree (1), which is 3:

     N
    / \
   3   N
  / \   \
 1   2   N
    / \   \
   N   1   N
  / \       \
 N   N       N
      \
       N

So the current maximum remains 4. Now move up to the parent node, and take the sum of the distance to the burning leaf (3) and the depth of the right sub-tree (4), which is 7:

     7
    / \
   3   4
  / \   \
 N   2   3
    / \   \
   N   1   2
  / \       \
 N   N       1
      \
       N

The new maximum is 7, and we've reached the root node, so 7 is the answer, as you can check by looking at which nodes are on fire after x seconds:

     3
    / \
   2   4
  / \   \
 3   1   5
    / \   \
   2   0   6
  / \       \
 3   3       7
      \
       4

Here's an example where the root isn't part of the longest path:

         N            N            3                  2
        / \          / \          / \                / \
       N   N        4   N        2   1              1   3
      / \          / \          / \                / \
     N   F        3   1        N   1              2   0
    /            /            /                  /
   N            2            N                  3
  /            /            /                  /
 N            1            N                  4

The largest value encountered was 4, in the parent of the leaf on fire.


Here's a simple JavaScript code snippet (I don't speak Python, but this should work as pseudo-code). It uses a hard-coded version of the tree in the first example from my answer. As you'll see, it does a single depth-first traversal of the tree.

function burn(root) {
    var maximum = 0;
    traverse(root);
    return maximum;

    function traverse(node) {
        if (node.onfire) {
            return {steps: 1, onfire: true};
        }
        var l = node.left ? traverse(node.left) : {steps: 0};
        var r = node.right ? traverse(node.right) : {steps: 0};
        if (l.onfire || r.onfire) {
            maximum = Math.max(maximum, l.steps + r.steps);
            return {steps: (l.onfire ? l.steps : r.steps) + 1, onfire: true};
        }
        return {steps: Math.max(l.steps, r.steps) + 1};
    }
}

var tree = {left: {left: {left: null, right: null}, right: {left: {left: {left: null, right: null}, right: {left: null, right: {left: null, right: null}}}, right: {left: null, right: null, onfire:true}}}, right: {left: null, right: {left: null, right: {left: null, right: {left: null, right: null}}}}}
document.write(burn(tree));
1

It can be done quickly with BFS:

class Node:
    def __init__(self, value):
        self.left = None
        self.right = None
        self.parent = None
        self.value = value

    def set_left(self, other):
        self.left = other
        other.parent = self

    def set_right(self, other):
        self.right = other
        other.parent = self

def get_distance_to_furthest(node):
    visited = set()
    queue = [(node, 0)]
    max_d = 0
    while queue:
        node, d = queue.pop(0)

        if node in visited:
            continue
        visited.add(node)

        max_d = max(d, max_d)

        if node.left:
            queue.append((node.left, d + 1))
        if node.right:
            queue.append((node.right, d + 1))
        if node.parent:
            queue.append((node.parent, d + 1))

    return max_d


# Sample code
root = Node(1)
root.set_left(Node(1))
root.set_right(Node(1))
root.left.set_left(Node(1))
root.left.set_right(Node(1))
root.left.right.set_left(Node(1))
root.left.right.set_right(Node(1))
root.right.set_right(Node(1))
root.right.right.set_right(Node(1))
root.right.right.right.set_right(Node(1))
print(
    "Starting from the given node, it will take %ds to burn the whole tree"
    % (get_distance_to_furthest(root.left.right))
)

A binary tree is just a special kind of graph, so you can walk through all nodes and keep track of the distance of each node to the node where the fire started. The result is the highest distance you have seen.

fafl
  • 6,094
  • 2
  • 23
  • 40
  • 4
    It's worth noting that having access to parent nodes is fairly non-standard for trees. – Bernhard Barker Oct 12 '18 at 23:19
  • When you try to get the distance from the `root.right.set_right`, it returns an error because there is no left. Where is your base case for where left or right is none? – Zeid Tisnes Oct 12 '18 at 23:30
  • @ZeidTisnes `root.right.set_right` is the function, try `root.right.right` – fafl Oct 13 '18 at 07:17
1

This one is my approach. Based on the node that has the leaf on its left or its right you have two possibilities:

  • explore the tree down
  • explore the tree to the other side

This two possibilities define two paths. The longest path is the answer to the problem (the longest path between the selected leaf and any other leaf). It is best understood in this figure on a given burn (red) node and the node that has the leaf reference (blue)

FIGURE

Programatically we explore the tree until we find the node that has the reference to the leaf. In that case we calculate the path that explores the rest of the tree (on the side of the original tree that has the leaf) and return 1 (to create the path to the other side with the recursion back).

MAP
  • 209
  • 2
  • 7
  • 1
    @m69 i rechecked the solution with other cases and it turns out the code does not work as expected. The solution still is about creating the longest path using recursion but i removed the code section to avoid confusion. – MAP Oct 13 '18 at 19:10
1

For those wondering what happened with this post, The solution used was this:

LeafSide = []

class Node:
    """Tree class."""

    def __init__(self, key):
        """Declare values of a node."""
        self.left = None
        self.right = None
        self.value = key


def leafHeight(root, leaf):
    """Height of the leaf."""
    if root is None:
        return 0
    else:
        if root.left is leaf:
            aux = 1 + leafHeight(root.right, leaf)
            LeafSide.append(aux)
            return 1
        if root.right is leaf:
            aux = 1 + leafHeight(root.left, leaf)
            LeafSide.append(aux)
            return 1
        return 1 + max(leafHeight(root.left, leaf), leafHeight(root.right, leaf))


def timeBurn(root, leaf):
    """How long will it take to burn the the node to furthest node."""
    hl = leafHeight(root.left, leaf)
    hr = leafHeight(root.right, leaf)
    opposite_LeafSide = 1 + hl + hr
    return max(opposite_LeafSide, LeafSide[0])


if __name__ == '__main__':
    root = Node(1)
    root.left = Node(1)
    root.right = Node(1)
    root.left.left = Node(1)
    root.left.right = Node(1)
    root.left.right.left = Node(1)
    root.left.right.right = Node(1)
    root.right.right = Node(1)
    root.right.right.right = Node(1)
    root.right.right.right.right = Node(1)
    print ("Starting from the given node, it will take %ds to burn the whole tree" % (timeBurn(root, root.left.right)))

Time: O(n)

Space: O(n)

If you notice, each node has a value of 1. The value of the node does not matter for this problem. It is just representing some value in it. The reason I have one is to think of a second (1 second Node). Thanks to everyone who helped me. I enjoyed reading all of the comments and approaches you guys were talking :). If you have a better idea in how to improve the code, feel free to comment below!

Zeid Tisnes
  • 374
  • 4
  • 17
0

Below is one of the solution to find the time taken to burn the tree ,given a source node (which can be a leave node or a non-leave node)

Approach to solve is as follow :

1) Find the source node in tree and find the height of the node (here we are storing it in variable "sourceDepth")

2) For all the ancestor of the given source node

 ->Take distance from the source node and present node 

 ->Find the height of the opposite subtree in which the source is not present

 ->Add both of the above + 1 (for the edge between ancestor and sub tree).Lets call this d

3) Take the max of all d's from step 2 and sourceDepth from step 1 which is the required answer.

For below example let source be 3:

     7
    / \
   8   4
  / \   \
 10   9   3
    / \   \
   0   11   2
             \
              1

depth of source (i.e 3) is : sourceDepth = 2

All ancestors of source are [7 , 4 ]

For ancestors 4 :

distance from source is 1 and there no sub tree in opposite direction of source (i.e source is in right sub tree and there is no left sub tree) . So d here is 1.

For ancestors 7

distance from source is 2 and the height of sub tree in opposite direction of source is 2 . So d here is 2+2+1=5. (1 is for the edge between 7 and 8)

Node 7 right sub tree for which height is = 2

   8   
  / \  
 10   9  
    / \  
   0   11 

Solution in this case will be Max of (2,1,5) which is 5 . So answer is 5

Java implemenation of above solution is :

static int max = Integer.MIN_VALUE;

private static int find(TreeNode<Integer> root, int source, int sourceDepth) {

    if (root == null) {
        return -1;
    }

    if (root.getData() == source) {
        sourceDepth = getDepth(root);
        return 0;
    }

    int left = find(root.getLeft(), source, sourceDepth);
    if (left != -1) {
        int rightDepth = getDepth(root.getRight()) + 1;
        max = Math.max(rightDepth + left + 1, sourceDepth);
        return left + 1;
    }

    int right = find(root.getRight(), source, sourceDepth);
    if (right != -1) {
        int leftDepth = getDepth(root.getRight()) + 1;
        max = Math.max(leftDepth + right + 1, sourceDepth);
        return right + 1;
    }

    return -1;
}

private static int getDepth(TreeNode<Integer> root) {

    if (root == null) {
        return -1;
    }

    return Math.max(getDepth(root.getLeft()), getDepth(root.getRight())) + 1;
}

Here source can be made any leave node which will give required answer asked here.

Farman
  • 66
  • 1
-2
//C++ implementation
#include <bits/stdc++.h>
using namespace std;
//Constructing tree
struct Node {
    int data;
    struct Node *left,*right;
    Node(int el){
        data=el;
        left=NULL;right=NULL;
    }
};
typedef struct Node Node;
Node *root=NULL;

//Constructing tree
void getparent(Node *n,int el,Node **temp){
    if(n==NULL)return;
    if(n->data==el){
        *temp=n;
    }
    getparent(n->left,el,temp);
    getparent(n->right,el,temp);
}

//Constructing tree
void create(){
    int el;
    cin>>el;
    Node *p = new Node(el);
    if(root==NULL){
        root=p;
    }else{
        Node *temp;
        int ch;
        cin>>ch;
        getparent(root,ch,&temp);
        if(temp->left==NULL){
            temp->left=p;
        }
        else{
            temp->right=p;
        }
    }
}
//Inorder traversal of tree
void print(Node *n){
    if(n!=NULL){
        print(n->left);
        cout<<n->data<<" ";
        print(n->right);
    }
}
//Height of tree from nth node
int height(Node *n){
    if(n==NULL)return 0;
    return max( height(n->left),height(n->right) )+1;
}

//Code For calculating max time in seconds when burnt at node with value k
int diameter(Node *n,int el,int *maxx){
    if(n!=NULL ){
        if(n->data==el)return  1;
        else {
            if(diameter(n->left,el,maxx)>0){
                if(*maxx<1+diameter(n->left,el,maxx)+height(n->right) )
                                *maxx=1+diameter(n->left,el,maxx)+height(n->right);
                return 1+diameter(n->left,el,maxx);
            }else if(diameter(n->right,el,maxx)>0) {
                if(*maxx<1+diameter(n->right,el,maxx)+height(n->left) )
                                *maxx=1+diameter(n->right,el,maxx)+height(n->left);
                return 1+diameter(n->right,el,maxx);
            }
            return 0;
        }
    }
    return 0;
}

int main() {
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        create();
    }
    print(root);
    cout<<"\n";
    int k;
    cin>>k;
    int maxx=0;
    diameter(root,k,&maxx);
    cout<<"Time taken will be : "<<maxx<<"\n";
}


//It is working fine . I made the tree to make it understandable.
Harsh
  • 7
  • 3
    The question was tagged as Python and has already a number of valid solutions. Why did you post a C++ answer? And an answer with only code without explanation is not really an answer, IMHO. – wovano Aug 17 '19 at 13:45
-4

This is off the top of my head, but on average the answer is ln(n) because this is the exact same algorithm as searching through a sorted binary tree.

edit: I was incorrect. I was thinking in my head 'quickest path from X to Y', which is ln(n), however this is actually 'longest path from X to anything'. Which is not binary search.

Jamie Clinton
  • 288
  • 1
  • 2
  • 9
  • 1
    For a given tree, the answer depends on the position of the burning leaf. So the answer isn't simply related to the number of leaves or the depth of the tree. – m69 ''snarky and unwelcoming'' Oct 12 '18 at 23:01
  • @m69 That would just be a coefficient though, and would get dropped in the complexity. ie O(2*ln) == O(ln) – Jamie Clinton Oct 12 '18 at 23:03
  • 2
    This is only true if the tree is balanced – fafl Oct 12 '18 at 23:03
  • @fafl an unbalanced tree would be the worst case, which is `n`, just like searching through a binary tree. – Jamie Clinton Oct 12 '18 at 23:06
  • 2
    You're thinking too much about worst case and O() notation; the question is about finding the exact distance in a specific case. – m69 ''snarky and unwelcoming'' Oct 12 '18 at 23:13
  • @m69 that is just an implementation of the algorithm. – Jamie Clinton Oct 12 '18 at 23:20
  • I was right, I just didn't couch it in the correct CS terminology. – Jamie Clinton Oct 12 '18 at 23:28
  • No, you weren't right. The question is about finding the exact time, not the computational complexity. Your answer assumes a balanced binary tree, which the OP's question does not assume. – Jim Mischel Oct 12 '18 at 23:50
  • @JimMischel the exact time is an implementation detail. Whether it is balanced or not only affects worst case. – Jamie Clinton Oct 12 '18 at 23:56
  • No, I'm not right because I assumed you could use the binary search algorithm, which depends on the tree being sorted. But in this case it would have to search every path, so it would be greater than N, not less than N. – Jamie Clinton Oct 13 '18 at 00:00
  • 1
    The OP's question is, given a *specific tree* and a *specific node*, how many time units will it take to burn the entire tree, assuming that a single node burns in time X, and spreads as described. Computational complexity is irrelevant except to say that the best case is X time units and the worst case is n*X time units. The average is irrelevant. – Jim Mischel Oct 13 '18 at 00:02
  • @JimMischel for coding purposes, but the general solution is what is important. – Jamie Clinton Oct 13 '18 at 00:06