【leetcode/DFS】克隆图(DFS初探)

题目描述:

给定无向连通图中一个节点的引用,返回该图的深拷贝(克隆)。图中的每个节点都包含它的值 valInt) 和其邻居的列表(list[Node])。

示例:

输入:
{"$id":"1","neighbors":[{"$id":"2","neighbors":[{"$ref":"1"},{"$id":"3","neighbors":[{"$ref":"2"},{"$id":"4","neighbors":[{"$ref":"3"},{"$ref":"1"}],"val":4}],"val":3}],"val":2},{"$ref":"4"}],"val":1}

解释:
节点 1 的值是 1,它有两个邻居:节点 2 和 4 。
节点 2 的值是 2,它有两个邻居:节点 1 和 3 。
节点 3 的值是 3,它有两个邻居:节点 2 和 4 。
节点 4 的值是 4,它有两个邻居:节点 1 和 3 。

思路:

  1. 首先要搞明白什么是深复制:深复制就是产生一个和原来对象属性完全一致,但是又互不影响的对象。比如,指针之间的赋值就是浅复制,为了达到指针的深复制,就得开辟一个一模一样的空间,再拿另一个指针副本指向它。
  2. 本题采用的数据结构——就是链表,不过不是线性的链表,是一个关于图的链表:数据域就是节点的label,指针域是一个指针的vector。由于是图,所以链表之间可能形成环
  3. 实现的大体思路:数据域直接复制。指针域形成了一个图,使用DFS进行复制(当然BFS也可)。
  4. 对更加深入的理解:DFS之前给的DFS的模板返回的是bool,这里返回的就是一个节点了,递归操作就是把节点加入我们的指针域中。
  5. Hash的选择:本题一个难点就是选择Hash的数据类型。在以前我们选择的都是set;但是这里我们却选择了unordered_map;原因如下:①我们遍历的是原来节点的邻居,如果节点已经被访问过了,我们应当添加之前深复制的该节点,这个怎么做到呢?——就是查看把原来节点当做map的key,深复制的节点当做map的value即可。②为啥是unordered?为啥又不是mulitimap? 前者是因为没必要用ordered,而且这样做也浪费时间,后者是因为我们是HashMap

AC代码:

#include<bits/stdc++.h>
using namespace std;

class Node {
public:
    int val;
    vector<Node*> neighbors;

    Node() {}

    Node(int _val) : val(_val) {}

    Node(int _val, vector<Node*> _neighbors) {
        val = _val;
        neighbors = _neighbors;
    }
};

Node *DFS(Node *node, unordered_map<Node*, Node*> &m) {    // node是带复制的节点,m是HashMap
  if (!node) return nullptr;
  if (m.count(node)) return m[node];
  Node *copy = new Node(node->val);   // 创建并给val属性赋值
  m[node] = copy;    // 及时更新HashMap
  for (auto neighbor : node->neighbors) {
    (copy->neighbors).push_back(DFS(neighbor, m));
  }
  return copy;
}

Node *cloneGraph(Node *node) {
  unordered_map<Node*, Node*> m;    // HashMap
  return DFS(node, m);
}

int main() {
  return 0;
}

其他经验:

  1. 我个人对链表还不是很敏感,链表都是一个节点代表整个链表的,而我在这却没想到。
  2. 复习了链表深复制的方法。
  3. 注意及时更新HashMap!!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值