算法课第17周第1题——133. Clone Graph

题目描述:

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
         / \
         \_/

程序代码:

解法1:BFS

/**
* Definition for undirected graph.
* struct UndirectedGraphNode {
*     int label;
*     vector<UndirectedGraphNode *> neighbors;
*     UndirectedGraphNode(int x) : label(x) {};
* };
*/
class Solution {
public:
	map<UndirectedGraphNode*, UndirectedGraphNode*> visit;


	UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
		if (node == NULL)
			return NULL;

		// 只有一个连通分量,不需要循环
		if (visit.find(node) == visit.end()) {
			bfs(node);
		}
		return visit[node];
	}

	void bfs(UndirectedGraphNode *node) {
		// 用原node的label新建并映射一个新的newNode
		UndirectedGraphNode* newNode = new UndirectedGraphNode(node->label);
		visit[node] = newNode;

		// 建立队列
		queue<UndirectedGraphNode*> q;
		q.push(node);

		// 循环直到队列为空
		while (!q.empty()) {
			UndirectedGraphNode* temp = q.front();
			vector<UndirectedGraphNode*> neighbor = temp->neighbors;
			q.pop();

			// 遍历访问点的邻接点
			for (vector<UndirectedGraphNode*>::iterator it = neighbor.begin(); it != neighbor.end(); ++it) {
				// 判断若没visit过,则复制旧邻接点生成一个新的node
				if (visit.find(*it) == visit.end()) {
					UndirectedGraphNode* newNode2 = new UndirectedGraphNode((*it)->label);
					visit[*it] = newNode2;
					q.push(*it);
				}
				// 将新node加入邻接点
				visit[temp]->neighbors.push_back(visit[*it]);
			}

		}
	}
};

解法2: DFS

class Solution {
public:
	map<UndirectedGraphNode*, UndirectedGraphNode*> visit;


	UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
		if (node == NULL)
			return NULL;

		// 只有一个连通分量,不需要循环所有连通分量
		// 若没有visit过
		if (visit.find(node) == visit.end()) {
			dfs(node);
		}
		return visit[node];
	}

	void dfs(UndirectedGraphNode* node) {		
		// 用原node的label新建并映射一个新的newNode
		UndirectedGraphNode* newNode = new UndirectedGraphNode(node->label);
		visit[node] = newNode;

		// 遍历原node的邻居
		vector<UndirectedGraphNode*> neighbor = node->neighbors;
		for (vector<UndirectedGraphNode*>::iterator it = neighbor.begin(); it != neighbor.end(); ++it) {
			UndirectedGraphNode* temp = *it;
			// 用dfs进行递归,得到各个邻居
			if (visit.find(*it) == visit.end()) {
				dfs(*it);
			}
			// 加入邻居节点
			newNode->neighbors.push_back(visit[*it]);
		}
	}
};

解法3:稍微简化的dfs

class Solution {
public:
	map<UndirectedGraphNode*, UndirectedGraphNode*> visit;


	UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
		if (node == NULL)
			return NULL;

		// 只有一个连通分量,不需要循环所有连通分量
		return dfs(node);
	}

 
	UndirectedGraphNode* dfs(UndirectedGraphNode* node) {
		// 若没有visit过
		if (visit.find(node) == visit.end()) {
			// 用原node的label新建并映射一个新的newNode
			UndirectedGraphNode* newNode = new UndirectedGraphNode(node->label);
			visit[node] = newNode;

			// 遍历原node的邻居
			vector<UndirectedGraphNode*> neighbor = node->neighbors;
			for (vector<UndirectedGraphNode*>::iterator it = neighbor.begin(); it != neighbor.end(); ++it) {
				UndirectedGraphNode* temp = *it;
				// 用dfs进行递归,得到各个邻居
				newNode->neighbors.push_back(dfs(temp));
			}
		}
		return visit[node];
	}
};

简要题解:

本题是一道关于图的问题。用到bfs和dfs算法。

先理清题意。本题的输入是一个无向图,要求复制这个无向图并输出。题中还给出了无向图节点的结构,包括一个唯一的label和一个vector,该向量中包含邻接节点。

很自然地,我想到使用bfs和dfs算法来解决这道问题。不过这道问题中有一个关键,就是visit数组要如何表示。因为不知道节点的总数量n,所以建立一个数组显然是不行的了,于是我想到使用stl库中的map来表示visit。 一开始,我打算用map<int, bool>来表示,即用每个节点唯一的label来映射一个布尔值,表示是否访问过,这也是最基本和普通的方法。但这样做了以后,我发现表示起来非常麻烦,既然都使用了map,不如直接将原节点映射到复制的节点,即用map<UndirectedGraphNode*, UndirectedGraphNode*>来表示,这样在表示访问了的同时,还可以直接映射到复制后的节点,操作起来就方便了很多。

接着,按常规的bfs的思路,建立队列,加入元素,循环取出元素,并处理节点元素中的向量,将新复制好的向量元素放入复制好的节点的邻接点向量中即可。

用dfs处理时同样简单,对邻接点向量中的每个元素递归调用dfs函数即可。

此外,我的解法3还对解法2的dfs做了稍微的简化,将解法2中void的dfs函数改为返回UndirectedGraphNode*,这样递归时可以直接将dfs(temp)加入邻接点向量,写起来稍微简单些。但也要注意,这样写的话cloneGraph函数中就没有了判断是否visit过的语句(因为直接return dfs(node)了),需要在dfs函数开始时加上这一句。


通过本题,我复习了一下关于图和dfs、bfs的知识点,接下来我还会再对其他知识点进行复习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值