Wednesday, February 4, 2015

Clone an Undirected Graph -- Leetcode

 [Question]

Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors.

OJ's undirected graph serialization: Nodes are labeled uniquely.
We use # as a separator for each node, and , as a separator for node label and each neighbor of the node. As an example, consider the serialized graph {0,1,2#1,2#2,2}.
The graph has a total of three nodes, and therefore contains three parts as separated by #.
  1. First node is labeled as 0. Connect node 0 to both nodes 1 and 2.
  2. Second node is labeled as 1. Connect node 1 to node 2.
  3. Third node is labeled as 2. Connect node 2 to node 2 (itself), thus forming a self-cycle.
Visually, the graph looks like the following:
       1
      / \
     /   \
    0 --- 2
         / \
         \_/

[Analysis]
This problem is similar with "Clone a Directed Acyclic Graph (DAG)". The basic approach is to use Breadth First Search.

The things to notice include: it may contains circles; it may have duplicated edges -- for example, two edges between node 1 and node 2. Those can be resolved by tracking the nodes cloned completely (edges and neighbors).

Update: DFS can provide more concise code.

[Solution]

//
// -- BFS --
//
/**
 * Definition for undirected graph.
 * struct UndirectedGraphNode {
 *     int label;
 *     vector<UndirectedGraphNode *> neighbors;
 *     UndirectedGraphNode(int x) : label(x) {};
 * };
 */
class Solution {
public:
    UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
        if (!node) return node;
       
        unordered_map<int, UndirectedGraphNode *> map;
        unordered_set<UndirectedGraphNode*> visited;
        queue<UndirectedGraphNode*> que;
       
        que.push(node);
        UndirectedGraphNode* new_node = new UndirectedGraphNode( node->label );
        map[node->label] = new_node;
       
        while (!que.empty()) {
            UndirectedGraphNode* front = que.front();
            que.pop();
            if (visited.find(front)!=visited.end())
                continue;
               
            for (auto p : front->neighbors) {
                if (map.find(p->label)==map.end()) {
                    UndirectedGraphNode* new_node = new UndirectedGraphNode( p->label );
                    map[p->label] = new_node;
                }   
                map[front->label]->neighbors.push_back(map[p->label]);
                if (p!=front && visited.find(p)==visited.end()) que.push(p);
            }
            visited.insert(front);
        }
        return new_node;
    }
};

//
//-- DFS --
//
class Solution {
    unordered_map<int, UndirectedGraphNode*> mNodes;
public:
    UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
        if (!node) return node;
        if (mNodes.count(node->label)) return mNodes[node->label];
       
        mNodes[node->label] = new UndirectedGraphNode(node->label);
        for (auto x: node->neighbors)
            mNodes[node->label]->neighbors.push_back( cloneGraph(x) );
           
        return mNodes[node->label];
    }
};

No comments:

Post a Comment