Saturday 12 November 2016

BTS - Find the Longest Sequence

1. Problem Description
Find the longest sequence in a binary tree

2. Data Structure and Algorithm
Pseudo-code:
    - Generate the depth map for each node
        * maximal depth of the left child
        * maximal depth of the right child
    - Go through then map and spot the node, Nx, with maximal sum of left and right depths
    - Find the deepest path, Pl of the left child of Nx
    - Find the deepest path, Pr of the right child of Nx
    - Revert Pl and join Pl, Nx and Pr as the longest sequence

Find the deepest path check details: BTS - Find the Deepest Path

3. C++ Implementation
Find the TreeNode definition, utility functions here: BST - Find Next In-Order Value and BTS - Print the First and Last Nodes of Each Level.

// ********************************************************************************
// Implementation
// ********************************************************************************
struct TreeNodeDepth{
    TreeNodeDepth()
        : depthOfLeft(0)
        , depthOfRight(0)
    {}
    TreeNodeDepth(const size_t left, const size_t right)
        : depthOfLeft(left)
        , depthOfRight(right)
    {}

    size_t Total() const {
        return depthOfLeft + depthOfRight;
    }
    // depth of left and right children
    size_t depthOfLeft;
    size_t depthOfRight;
};

template <typename T>
using DepthMap = std::unordered_map<TreeNode<T>*, TreeNodeDepth>;

template <typename T>
size_t GenerateDepthMap(TreeNode<T> *root, DepthMap<T> &depth) {
    if (!root) {
        // special case - NULL pointer
        return 0;
    }

    // depth of this node and save into the map
    size_t leftDepth = GenerateDepthMap(root->left, depth);
    size_t rightDepth = GenerateDepthMap(root->right, depth);
    depth.insert(std::make_pair(root, TreeNodeDepth(leftDepth, rightDepth)));

    // return the maximal depth of left and right path
    return leftDepth >= rightDepth ? (leftDepth + 1) : (rightDepth + 1);
}

template <typename T>
std::list<TreeNode<T>*> FindTheLongestSequence(TreeNode<T> *root)
{
    if (!root) {
        // special case - NULL pointer
        return std::list<TreeNode<T>*>();
    }

    // Generate the depth map
    DepthMap<T> depth;
    GenerateDepthMap(root, depth);
    size_t totalLength = 0;
    TreeNode<T>* nodeWithTheLongestSeq = NULL;
    auto itEnd = depth.rend();
    // Loop through the depth map and find the longest sequence
    // Spot the node with largest sum of depth of left and right children
    for (auto it = depth.rbegin(); it != itEnd; ++it) {
        if (it->second.Total() > totalLength) {
            nodeWithTheLongestSeq = it->first;
            totalLength = it->second.Total();
        }
    }
   
    // Find the deepest path of the left child
    std::list<TreeNode<T>*> leftBranchPath = 
        FindTheDeepestPath(nodeWithTheLongestSeq->left);
    // Find the deepest path of the right child
    std::list<TreeNode<T>*> rightBranchPath =
        FindTheDeepestPath(nodeWithTheLongestSeq->right);
    // Join them to form the sequence
    leftBranchPath.reverse();
    leftBranchPath.push_back(nodeWithTheLongestSeq);
    leftBranchPath.splice(leftBranchPath.end(), rightBranchPath);
    return leftBranchPath;
}

// ********************************************************************************
// Test
// ********************************************************************************
void TestFindTheLongestSeq()
{
    std::vector<double> input = { 1.0, 2.0, 3.0, 4.0, 5.0 };
    TreeNode<double> *root = NULL;
    auto path = FindTheLongestSequence(root);
    assert(path.empty() == true);
    //              3
    //      1               4
    //          2               5
    root = ConstructTreeOnSortedValueBFS(input);
    path = FindTheLongestSequence(root);
    TestResult<double>(path, { 2.0, 1.0, 3.0, 4.0, 5.0 });
    
    input = { 6.0, 7.0, 8.0, 9.0 };
    TreeNode<double> *subTree1 = ConstructTreeOnSortedValueDFS(input);
    input = { 10.0, 11.0, 12.0, 13.0 , 14.0 };
    TreeNode<double> *subTree2 = ConstructTreeRecursive(input);
    input = { 15.0, 16.0, 17.0, 18.0 };
    TreeNode<double> *subTree3 = ConstructTreeOnSortedValueDFS(input);
    input = { 19.0, 20.0, 21.0, 22.0 , 23.0 };
    TreeNode<double> *subTree4 = ConstructTreeRecursive(input);

    TreeNode<double> *leftestNode = FindLeftestNode(root);
    assert(leftestNode != NULL);
    leftestNode->left = subTree1;
    //              3
    //         1        4
    //      8     2        5
    //    6   9
    //  7
    path = FindTheLongestSequence(root);
    TestResult<double>(path, { 7.0, 6.0, 8.0, 1.0, 3.0, 4.0, 5.0 });

    TreeNode<double> *rightestNode = FindRightestNode(root);
    assert(rightestNode != NULL);
    rightestNode->left = subTree2;
    //              3
    //         1        4
    //      8     2         5
    //    6   9          12
    //  7            10      13
    //                    11      14
    path = FindTheLongestSequence(root);
    TestResult<double>(path, { 7.0, 6.0, 8.0, 1.0, 3.0, 4.0, 5.0, 12.0, 10.0, 11.0 });
    
    TreeNode<double> *firstLeftRighestNode = FindRightestNode(root->left);
    assert(firstLeftRighestNode != NULL);
    firstLeftRighestNode->right = subTree3;
    //                    3
    //         1              4
    //      8     2                   5
    //    6   9     17          12
    //  7         15   18   10       13
    //                16          11      14
    path = FindTheLongestSequence(root);
    TestResult<double>(path, { 16.0, 15.0, 17.0, 2.0, 1.0, 3.0,
                               4.0, 5.0, 12.0, 10.0, 11.0 });
    
    TreeNode<double> *firstRightLeftestNodeOfS2 = FindRightestNode(subTree2->left);
    assert(firstRightLeftestNodeOfS2 != NULL);
    firstRightLeftestNodeOfS2->left = subTree4;
    //                    3
    //         1              4
    //      8     2                   5
    //    6   9     17          12
    //  7         15   18   10       13
    //               16           11      14
    //                         21
    //                    19     22
    //                        20       23
    path = FindTheLongestSequence(root);
    TestResult<double>(path, { 16.0, 15.0, 17.0, 2.0, 1.0, 3.0,
        4.0, 5.0, 12.0, 10.0, 11.0, 21.0, 19.0, 20.0 });
    
    TreeNode<double> *rightestNodeOfS2 = FindRightestNode(subTree2);
    assert(rightestNodeOfS2 != NULL);
    for (size_t i = 0; i < 8; ++i) {
        rightestNodeOfS2->right = new TreeNode<double>(100.0 + i);
        rightestNodeOfS2 = rightestNodeOfS2->right;
    }
    TreeNode<double> *rightestNodeOfS4 = FindRightestNode(subTree4);
    assert(rightestNodeOfS4 != NULL);
    for (size_t i = 0; i < 4; ++i) {
        rightestNodeOfS4->left = new TreeNode<double>(50.0 + i);
        rightestNodeOfS4 = rightestNodeOfS4->left;
    }
    //                    3
    //         1              4
    //      8     2                   5
    //    6   9     17          12
    //  7         15   18   10       13
    //                16          11      14
    //                         21              100
    //                    19     22             101
    //                      20       23            102
    //                             50                   103
    //                           51                       104
    //                         52                            105
    //                       53                                106
    //                                                              107
    path = FindTheLongestSequence(root);
    TestResult<double>(path, { 53.0, 52.0, 51.0, 50.0, 23.0, 22.0, 21.0,
        11.0, 10.0, 12.0, 13.0, 14.0, 100.0, 101.0, 102.0, 103.0, 104.0,
        105.0, 106.0, 107.0 });
    // clean up
    DeleteTree_TD(&root);
}


BTS - Find the Deepest Path

1. Problem Description
Find the deepest path from root to its leaf node.

2. Data Structure and Algorithm
Recursive implementation pseudo-code:
    - Get the deepest path of the path of the left child
    - Get the deepest path of the path of the right child
    - Return the deepest path of the left child if it is longer than the right
        * Return the deepest path of the right child if it is longer than the left
    - Special case: Return null path if this node is empty

Loop implementation pseudo-code:
    - Generate a stack map
        * In the order of each level
        * Each level is separated by a NULL pointer
        * Start from the root until the leaf nodes of the lowest level
    - Take the stack map from backwards
        * Take the first node of the lowest level (one of deepest path), Pn
        * Populate out node of each level (use separator of NULL pointer)
        * Find the parent of Pn -- Pn-1
        * Loop the stack map until the root

3. C++ Implementation
Find the TreeNode definition, utility functions here: BST - Find Next In-Order Value and BTS - Print the First and Last Nodes of Each Level.

// ********************************************************************************
// Implementation
// ********************************************************************************
// Recursive implementation
template <typename T>
std::list<TreeNode<T>*> FindTheDeepestPath_R(TreeNode<T> *root)
{
    if (!root) {
        return std::list<TreeNode<T>*>();
    }
    // left path
    std::list<TreeNode<T>*> leftPath = FindTheDeepestPath_R(root->left);
    leftPath.emplace_front(root);
    // right path
    std::list<TreeNode<T>*> rightPath = FindTheDeepestPath_R(root->right);
    rightPath.emplace_front(root);

    return leftPath.size() >= rightPath.size() ? leftPath : rightPath;
}

// Loop implementation
template <typename T>
std::list<TreeNode<T>*> FindTheDeepestPath(TreeNode<T> *root)
{
    if (!root) {
        return std::list<TreeNode<T>*>();
    }

    std::stack<TreeNode<T>*> nodesInLevel;
    std::queue<TreeNode<T>*> searchQueue;
    searchQueue.push(root);
    searchQueue.push(NULL);
    TreeNode<T> * curNode = NULL; // empty node as separater
    while (!searchQueue.empty()) {
        curNode = searchQueue.front();
        searchQueue.pop();
        if (curNode) {
            if (curNode->left) {
                searchQueue.push(curNode->left);
            }
            if (curNode->right) {
                searchQueue.push(curNode->right);
            }
        }
        else if (!searchQueue.empty()) {
            searchQueue.push(curNode);
        }

        nodesInLevel.push(curNode);
    }

    // nodeInLevel should have all nodes
    // each level is separated by empty nodes
    // start with root and end with empty nodes
    std::list<TreeNode<T>*> path;
    std::list<TreeNode<T>*> nodesInSameLevel;
    while (!nodesInLevel.empty()) {
        curNode = nodesInLevel.top();
        nodesInLevel.pop();
        if (!curNode) {
            // found a level
            if (!nodesInSameLevel.empty()) {
                if (path.empty()) {
                    // it might have multipile path
                    // take the first one avaialbel
                    path.push_back(*nodesInSameLevel.rbegin());
                }
                else {
                    auto itEnd = nodesInSameLevel.cend();
                    for (auto it = nodesInSameLevel.cbegin(); it != itEnd; ++it) {
                        if ((*it)->left == path.back() || (*it)->right == path.back()) {
                            // find its parent node
                            path.push_back(*it);
                            break;
                        }
                    }
                }
            }
            nodesInSameLevel.clear();
        }
        else {
            nodesInSameLevel.push_back(curNode);
        }
    }
    path.push_back(curNode);
    path.reverse();  
    return path;
}

// ********************************************************************************
// Test
// ********************************************************************************
void TestFindTheDeepestPath()
{
    std::vector<double> input = { 1.0, 2.0, 3.0, 4.0, 5.0};
    TreeNode<double> *root = NULL;
    auto path = FindTheDeepestPath(root);
    assert(path.empty() == true);
    path = FindTheDeepestPath_R(root);
    assert(path.empty() == true);
    //              3
    //      1               4
    //          2               5
    root = ConstructTreeOnSortedValueBFS(input);
    path = FindTheDeepestPath(root);
    TestResult<double>(path, {3.0, 1.0, 2.0});
    path = FindTheDeepestPath_R(root);
    TestResult<double>(path, { 3.0, 1.0, 2.0 });

    input = { 6.0, 7.0, 8.0, 9.0 };
    TreeNode<double> *subTree1 = ConstructTreeOnSortedValueDFS(input);
    input = { 10.0, 11.0, 12.0, 13.0 , 14.0};
    TreeNode<double> *subTree2 = ConstructTreeRecursive(input);
    input = { 15.0, 16.0, 17.0, 18.0 };
    TreeNode<double> *subTree3 = ConstructTreeOnSortedValueDFS(input);
    input = { 19.0, 20.0, 21.0, 22.0 , 23.0 };
    TreeNode<double> *subTree4 = ConstructTreeRecursive(input);

    TreeNode<double> *leftestNode = FindLeftestNode(root);
    assert(leftestNode != NULL);
    leftestNode->left = subTree1;
    //              3
    //         1        4
    //      8     2        5
    //    6   9
    //  7
    path = FindTheDeepestPath(root);
    TestResult<double>(path, { 3.0, 1.0, 8.0, 6.0, 7.0 });
    path = FindTheDeepestPath_R(root);
    TestResult<double>(path, { 3.0, 1.0, 8.0, 6.0, 7.0 });

    TreeNode<double> *rightestNode = FindRightestNode(root);
    assert(rightestNode != NULL);
    rightestNode->left = subTree2;
    //              3
    //         1        4
    //      8     2         5
    //    6   9          12
    //  7            10      13
    //                  11      14
    path = FindTheDeepestPath(root);
    TestResult<double>(path, { 3.0, 4.0, 5.0, 12.0, 10.0, 11.0 });
    path = FindTheDeepestPath_R(root);
    TestResult<double>(path, { 3.0, 4.0, 5.0, 12.0, 10.0, 11.0 });

    TreeNode<double> *firstLeftRighestNode = FindRightestNode(root->left);
    assert(firstLeftRighestNode != NULL);
    firstLeftRighestNode->right = subTree3;
    //                    3
    //         1              4
    //      8     2                   5
    //    6   9     17          12
    //  7         15   18   10       13
    //               16            11      14
    path = FindTheDeepestPath(root);
    TestResult<double>(path, { 3.0, 1.0, 2.0, 17.0, 15.0, 16.0 });
    path = FindTheDeepestPath_R(root);
    TestResult<double>(path, { 3.0, 1.0, 2.0, 17.0, 15.0, 16.0 });

    TreeNode<double> *firstRightLeftestNodeOfS2 = FindRightestNode(subTree2->left);
    assert(firstRightLeftestNodeOfS2 != NULL);
    firstRightLeftestNodeOfS2->left = subTree4;
    //                    3
    //         1              4
    //      8     2                   5
    //    6   9     17          12
    //  7         15   18   10       13
    //               16           11      14
    //                         21
    //                    19     22
    //                       20       23
    path = FindTheDeepestPath(root);
    TestResult<double>(path, { 3.0, 4.0, 5.0, 12.0, 10.0, 11.0, 21.0, 19.0, 20.0 });
    path = FindTheDeepestPath_R(root);
    TestResult<double>(path, { 3.0, 4.0, 5.0, 12.0, 10.0, 11.0, 21.0, 19.0, 20.0 });

    TreeNode<double> *rightestNodeOfS2 = FindRightestNode(subTree2);
    assert(rightestNodeOfS2 != NULL);
    for (size_t i = 0; i < 8; ++i) {
        rightestNodeOfS2->right = new TreeNode<double>(100.0 + i);
        rightestNodeOfS2 = rightestNodeOfS2->right;
    }
    //                    3
    //         1              4
    //      8     2                   5
    //    6   9     17          12
    //  7         15   18   10     13
    //              16           11      14
    //                        21              100
    //                    19     22            101
    //                      20       23          102
    //                                                  103
    //                                                     104
    //                                                        105
    //                                                          106
    //                                                            107
    // clean up
    path = FindTheDeepestPath(root);
    TestResult<double>(path, { 3.0, 4.0, 5.0, 12.0, 13.0, 14.0, 100.0, 101.0,
                               102.0, 103.0, 104.0, 105.0, 106.0, 107.0 });
    path = FindTheDeepestPath_R(root);
    TestResult<double>(path, { 3.0, 4.0, 5.0, 12.0, 13.0, 14.0, 100.0, 101.0,
                               102.0, 103.0, 104.0, 105.0, 106.0, 107.0 });

   // clean up
    DeleteTree_TD(&root);
}