Tree Add Removal

// At DoorDash, menus are updated daily even hourly to keep them up-to-date. Each menu can be regarded as a tree.
// When the merchant sends us the latest menu, can we calculate how many nodes has changed?

// Assume there are no duplicate nodes with the same key.

// Output: Return the number of changed nodes in the tree.

// Example 1
// Existing Menu in our system:

// Existing tree
//                           a(1, T)
//                           /     \
//                    b(2, T)     c(3, T)
//                      / \              \
//            d(4, T) e(5, T)        f(6, T)
//
// Legend: In "a(1, T)", a is the key, 1 is the value, T is True for active status 

// New Menu sent by the Merchant:

// New tree
//                  a(1, T)
//                     |
//                  c(3, F)
//                     |
//                 f(66, T)
//
// Expected Answer: 5 Explanation: Node b, Node d, Node e are automatically set to inactive.
// The active status of Node c and the value of Node f changed as well.

// Example 2
// Existing Menu in our system:

// Existing tree
//                           a(1, T)
//                            /    \
//                    b(2, T)      c(3, T)
//                       / \           \
//             d(4, T) e(5, T)     g(7, T)
// New Menu sent by the Merchant:

// New tree
//                         a(1, T)
//                       /          \
//                 b(2, T)         c(3, T)
//                /  |    \              \
//       d(4, T) e(5, T)  f(6, T)      g(7, F)
//
// Expected Answer: 2 Explanation: Node f is a newly-added node. Node g changed from Active to inactive
// follow - up是输出变化的节点。具体可以参考这个帖子

#include <string>
#include <vector>
#include <iostream>

using namespace std;

class Node {
public:
    string key;
    int val;
    bool isActive;

    vector<Node*> children;
    Node(string k, int v): key(k), val(v), isActive(true) {}
    Node(string k, int v, bool active) : key(k), val(v), isActive(active) {}

    void addChild(Node* n) {
        children.push_back(n);
    } 
};

// hashmap keep track of key and number of nodes under that subtree.
unordered_map<string, int> om;
unordered_map<string, int> nm;

int count(Node* n, unordered_map<string, int>& m) {
    if (!n) {
        return 0;
    }

    int res = 1;
    for (Node* child : n->children) {
        res += count(child, m);
    }
    
    m[n->key] = res;
    return res;
}

int findDiffNodes(Node* oldMenu, Node* newMenu) {
    // Both trees are empty, they are the same tree
    if (!oldMenu && !newMenu) {
        return 0;
    }
    // Only one of the trees is not null
    // Or if the key of both trees are different, then return
    // the node count of both trees (which could be zero or one of them)
    if ((!oldMenu && newMenu)
    || (!newMenu && oldMenu)
    || (newMenu->key != oldMenu->key)) {
        return om[oldMenu->key] + nm[newMenu->key];
    }

    int res = 0;
    // If their values are different
    // Then we include the current nodes of the two trees as the only diff and then
    // compute the diff of the children
    if (oldMenu->val != newMenu->val) {
        res += 1;
    } else if (oldMenu->isActive != newMenu->isActive) {
        res += 1;
    }

    unordered_map<string, Node*> m1;
    for (Node* n : oldMenu->children) {
        m1[n->key] = n;
    }
    unordered_map<string, Node*> m2;
    for (Node* n : newMenu->children) {
        m2[n->key] = n;
    }

    for (auto i : m1) {
        if (!m2.count(i.first)) {
            res += om[i.second->key];
        } else {
            Node* child2 = m2[i.first];
            res += findDiffNodes(i.second, child2);
            m2.erase(i.first);
        }
    }

    for (auto i : m2) {
        res += nm[i.second->key];
    }

    return res;
}

int diff(Node* oldMenu, Node* newMenu) {
    count(oldMenu, om);
    count(newMenu, nm);
    return findDiffNodes(oldMenu, newMenu);
}

int main() {
    // Example 1
// Existing Menu in our system:

// Existing tree
//                           a(1, T)
//                           /     \
//                    b(2, T)     c(3, T)
//                      / \             \
//            d(4, T) e(5, T)        f(6, T)
//
// Legend: In "a(1, T)", a is the key, 1 is the value, T is True for active status 

// New Menu sent by the Merchant:

// New tree
//                  a(1, T)
//                     |
//                  c(3, F)
//                     |
//                 f(66, T)
//
// Expected Answer: 5 Explanation: Node b, Node d, Node e are automatically set to inactive.
// The active status of Node c and the value of Node f changed as well.

    Node* a = new Node("a", 1, true);
    Node* b = new Node("b", 2, true);
    Node* c = new Node("c", 3, true);
    Node* d = new Node("d", 4, true);
    Node* e = new Node("e", 5, true);
    Node* f = new Node("f", 6, true);

    // Existing tree
    a->addChild(b);
    a->addChild(c);
    b->addChild(d);
    b->addChild(e);
    c->addChild(f);

    Node* a1 = new Node("a", 1, true);
    Node* c1 = new Node("c", 3, false);
    Node* f1 = new Node("f", 66, true);

    a1->addChild(c1);
    c1->addChild(f1);

    cout << diff(a1, a) << endl;

// Example 2
// Existing Menu in our system:

// Existing tree
//                           a(1, T)
//                            /    \
//                    b(2, T)      c(3, T)
//                       / \           \
//             d(4, T) e(5, T)     g(7, T)
// New Menu sent by the Merchant:

// New tree
//                         a(1, T)
//                       /          \
//                 b(2, T)         c(3, T)
//                /  |    \              \
//       d(4, T) e(5, T)  f(6, T)      g(7, F)
//
// Expected Answer: 2 Explanation: Node f is a newly-added node. Node g changed from Active to inactive

    Node* a3 = new Node("a", 1, true);
    Node* b3 = new Node("b", 2, true);
    Node* c3 = new Node("c", 3, true);
    Node* d3 = new Node("d", 4, true);
    Node* e3 = new Node("e", 5, true);
    Node* g3 = new Node("g", 7, true);
    a3->addChild(b3);
    a3->addChild(c3);
    b3->addChild(d3);
    b3->addChild(e3);
    c3->addChild(g3);

    Node* a4 = new Node("a", 1, true);
    Node* b4 = new Node("b", 2, true);
    Node* c4 = new Node("c", 3, true);
    Node* d4 = new Node("d", 4, true);
    Node* e4 = new Node("e", 5, true);
    Node* f4 = new Node("f", 6, true);
    Node* g4 = new Node("g", 7, false);
    a4->addChild(b4);
    a4->addChild(c4);
    b4->addChild(d4);
    b4->addChild(e4);
    b4->addChild(f4);
    c4->addChild(g4);

    cout << diff(a4, a3) << endl;

    return 0;
}```

Last updated