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);
}


No comments:

Post a Comment