算法设计Week3 LeetCode Algorithms Problem #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 #.

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来获取,这样可以保证代码的正确性。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值