您的位置:首页 > 编程语言 > Go语言

算法设计Week3 LeetCode Algorithms Problem #133 Clone Graph

2017-03-11 20:57 369 查看

题目描述:

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 #.

First node is labeled as 0. Connect node 0 to both nodes 1 and 2.

Second node is labeled as 1. Connect node 1 to node 2. 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
/ \
\_/


题目中给出的图的结构体如下:

struct UndirectedGraphNode {
int label;
vector<UndirectedGraphNode *> neighbors;
UndirectedGraphNode(int x) : label(x) {};
};


解法一(BFS):

广度优先算法(BFS)主要思路是首先看一个节点最多能够访问到哪些节点,再依次对这些节点进行访问和检索。BFS除了原本的图之外,还需要用到一个队列(queue)用于存储要访问的节点,以及一个标记节点是否已被访问的数组。

在本题中,除了要考虑节点是否已访问,还要考虑原节点和新创建的节点间的对应关系。在后边出现的节点q也有可能会和前边出现的节点p有边,p节点已经被访问过,应该有对应的新节点p_new,但p_new却不一定好找。也就是说,我们需要保存一张新旧节点对应关系的“地图”。所以需要使用map的结构。这里使用hash map来实现。

实现代码如下:

class Solution {
public:
UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
if(!node) return NULL;

unordered_map<UndirectedGraphNode*, UndirectedGraphNode*> nodeList;
UndirectedGraphNode *new_node = new UndirectedGraphNode(node->label);
nodeList[node] = new_node;

queue<UndirectedGraphNode *> tovisit;
tovisit.push(node);
while(!tovisit.empty()){
UndirectedGraphNode *cur_node = tovisit.front();
tovisit.pop();
for(UndirectedGraphNode* neigh : cur_node -> neighbors){
if(nodeList.find(neigh) == nodeList.end()){
UndirectedGraphNode *new_neigh = new UndirectedGraphNode(neigh->label);
nodeList[neigh] = new_neigh;
tovisit.push(neigh);
}
nodeList[cur_node]->neighbors.push_back(nodeList[neigh]);
}
}
return new_node;
}
};


解法二(DFS):

深度优先遍历(DFS)基于的想法很简单,就是探索迷宫需要的“线”和“粉笔”。线用来在探索迷宫走到尽头时返回出发点,而粉笔则用来标注已经访问过哪些点。类似地,DFS首先查看一个节点最远能够遍历到哪个节点,然后返回查看。这样,这个算法需要用到一个栈(stack)用于存储要访问的节点(与“线”的作用相同),以及一个标记节点是否已被访问的数组(与“粉笔”的作用相同)。

函数的递归调用是自动以栈的形式实现的,因此可以使用递归的方式来快速有效地完成DFS算法:

class Solution {
public:
UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
if(!node) return NULL;
UndirectedGraphNode *new_node = new UndirectedGraphNode(node->label);
nodeList[node] = new_node;
DFS(node);
return new_node;
}
void DFS(UndirectedGraphNode *cur_node){
for(UndirectedGraphNode* neigh : cur_node -> neighbors){
if(nodeList.find(neigh) == nodeList.end()){
UndirectedGraphNode *new_node = new UndirectedGraphNode(neigh->label);
nodeList[neigh] = new_node;
DFS(neigh);
}
nodeList[cur_node]->neighbors.push_back(nodeList[neigh]);
}

}
private:
unordered_map<UndirectedGraphNode *, UndirectedGraphNode *> nodeList;
};


Notes:

这里说一些在编程过程中出现的问题:

1、要注意考虑图为空时的情况。

2、要仔细考虑每一步用到的是原节点还是新节点,如果使用的是新节点的话,最好使用哈希表
nodeList
来获取,这样可以保证代码的正确性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode 算法