算法设计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来获取,这样可以保证代码的正确性。
相关文章推荐
- 算法设计Week16 LeetCode Algorithms Problem #322 Coin Change
- 【Leetcode】:LRU Cache_缓存淘汰算法LRU的设计与实现
- LeetCode133——Clone Graph
- 算法设计与分析 HW6:LeetCode 54
- 算法设计Week10 LeetCode Algorithms Problem #213 House Robber II
- 算法分析与设计课程(10):【leetcode】Simplify Path
- 算法设计Week8 LeetCode Algorithms Problem #198 House Robber
- 【Java、算法】Princeton Algorithms Part I Week 1 Exercise
- 算法分析与设计课程(14):【leetcode】 Maximal Square
- 算法分析与设计课程(6):【leetcode】Sudoku
- 算法分析与设计课程(11):【leetcode】Gray Code
- Lecture Note - 北大 - 算法设计与分析 Design and Analysis of Algorithms - Wanling Qu
- LeetCode133—Clone Graph
- [LeetCode]题解(python):133-Clone Graph
- 算法分析与设计课程(7):【leetcode】Reverse Nodes in k-Group
- [LeetCode]133 Clone Graph
- [LeetCode]: 133: Clone Graph
- 算法Week11.01 - LeetCode 452. Minimum Number of Arrows to Burst Balloons
- 算法设计Week8 LeetCode Algorithms Problem #70 Climbing Stairs
- 算法设计Week13 LeetCode Algorithms Problem #64 Minimum Path Sum