LeetCode 力扣 133. 克隆图

鬼脸儿
• 阅读 1801

题目描述(中等难度)

LeetCode 力扣 133. 克隆图

复制一个图,图的节点定义如下。

class Node {
    public int val;
    public List<Node> neighbors;

    public Node() {}

    public Node(int _val,List<Node> _neighbors) {
        val = _val;
        neighbors = _neighbors;
    }
};

neighbors 是一个装 Nodelist ,因为对象的话,java 变量都存储的是引用,所以复制的话要新 new 一个 Node 放到 neighbors

思路分析

这个题其实就是对图进行一个遍历,通过 BFS 或者 DFS。需要解决的问题就是怎么添加当前节点的 neighbors,因为遍历当前节点的时候,它的邻居节点可能还没有生成。

解法一 BFS

先来一个简单粗暴的想法。

首先对图进行一个 BFS,把所有节点 new 出来,不处理 neighbors ,并且把所有的节点存到 map 中。

然后再对图做一个 BFS,因为此时所有的节点已经创建了,只需要更新所有节点的 neighbors

public Node cloneGraph(Node node) {
    if (node == null) {
        return node;
    }
    //第一次 BFS
    Queue<Node> queue = new LinkedList<>();
    Map<Integer, Node> map = new HashMap<>();
    Set<Integer> visited = new HashSet<>();
    queue.offer(node);
    visited.add(node.val);
    while (!queue.isEmpty()) {
        Node cur = queue.poll();
        //生成每一个节点
        Node n = new Node();
        n.val = cur.val;
        n.neighbors = new ArrayList<Node>();
        map.put(n.val, n);
        for (Node temp : cur.neighbors) {
            if (visited.contains(temp.val)) {
                continue;
            }
            queue.offer(temp);
            visited.add(temp.val);
        }
    }

    //第二次 BFS 更新所有节点的 neightbors
    queue = new LinkedList<>();
    queue.offer(node);
    visited = new HashSet<>();
    visited.add(node.val);
    while (!queue.isEmpty()) {
        Node cur = queue.poll();
        for (Node temp : cur.neighbors) {
            map.get(cur.val).neighbors.add(map.get(temp.val));
        }
        for (Node temp : cur.neighbors) {
            if (visited.contains(temp.val)) {
                continue;
            }
            queue.offer(temp);
            visited.add(temp.val);
        }
    }
    return map.get(node.val);
}

当然再仔细思考一下,其实我们不需要两次 BFS

我们要解决的问题是遍历当前节点的时候,邻居节点没有生成,那么我们可以一边遍历一边生成邻居节点,就可以同时更新 neighbors 了。

同样需要一个 map 记录已经生成的节点。

public Node cloneGraph(Node node) {
    if (node == null) {
        return node;
    }
    Queue<Node> queue = new LinkedList<>();
    Map<Integer, Node> map = new HashMap<>();
    queue.offer(node);
    //先生成第一个节点
    Node n = new Node();
    n.val = node.val;
    n.neighbors = new ArrayList<Node>();
    map.put(n.val, n);
    while (!queue.isEmpty()) {
        Node cur = queue.poll();
        for (Node temp : cur.neighbors) {
            //没有生成的节点就生成
            if (!map.containsKey(temp.val)) {
                n = new Node();
                n.val = temp.val;
                n.neighbors = new ArrayList<Node>();
                map.put(n.val, n);
                queue.offer(temp);
            }
            map.get(cur.val).neighbors.add(map.get(temp.val));
        }
    }

    return map.get(node.val);
}

解法二 DFS

DFS 的话用递归即可,也用一个 map 记录已经生成的节点。

public Node cloneGraph(Node node) {
    if (node == null) {
        return node;
    }
    Map<Integer, Node> map = new HashMap<>();
    return cloneGrapthHelper(node, map);
}

private Node cloneGrapthHelper(Node node, Map<Integer, Node> map) {
    if (map.containsKey(node.val)) {
        return map.get(node.val);
    }
    //生成当前节点
    Node n = new Node();
    n.val = node.val;
    n.neighbors = new ArrayList<Node>();
    map.put(node.val, n);
    //添加它的所有邻居节点
    for (Node temp : node.neighbors) {
        n.neighbors.add(cloneGrapthHelper(temp, map));
    }
    return n;
}

这道题本质上就是对图的遍历,只要想到用 map 去存储已经生成的节点,题目基本上就解决了。

更多详细通俗题解详见 leetcode.wang
点赞
收藏
评论区
推荐文章
美凌格栋栋酱 美凌格栋栋酱
10个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Easter79 Easter79
4年前
Vue 仿钉钉流程图(流程节点绘制 vue+Ant【如果用其他UI库需要替换几个组件】 附 demo)
Vue仿钉钉流程图(流程节点绘制vueAntDesignofVue)仿钉钉流程图Api包括:一维数组传参,获取单节点数据,返回所有节点组成的一位数组生成每个节点的父节点Id集合很多公司后台管理系统都需要画流程图,功能大同小异,所以,仿照钉钉管理
Wesley13 Wesley13
4年前
java 选择结构if
图11     if…elseif…else语句的流程图!(https://oscimg.oschina.net/oscnet/421d60a830835fe0a86905053cf0c13578d.png)选择结构if语句与三元运算转换  三元运算符,它和ifelse语句类似,语法如下:  判断条件?表达式1:表达式2
梦
4年前
微信小程序new Date()转换时间异常问题
微信小程序苹果手机页面上显示时间异常,安卓机正常问题image(https://imghelloworld.osscnbeijing.aliyuncs.com/imgs/b691e1230e2f15efbd81fe11ef734d4f.png)错误代码vardate'2021030617:00:00'vardateT
Wesley13 Wesley13
4年前
2019 年 CNCF 中国云原生调查报告
!头图.jpg(https://ucc.alicdn.com/pic/developerecology/6db0c465111b4d9a96eb1ffe85c00e7a.jpg)中国72%的受访者生产中使用Kubernetes在CNCF,为更好地了解开源和云原生技术的使用,我们定期调查社区。这是第三次中国云原生调查,以中文进行
Wesley13 Wesley13
4年前
mysql查询每个学生的各科成绩,以及总分和平均分
今天看一个mysql教程,看到一个例子,感觉里面的解决方案不是很合理。问题如下:有学生表:!在这里插入图片描述(https://oscimg.oschina.net/oscnet/07b001b0c6cb7e0038a9299e768fc00a0d3.png)成绩表:!在这里插入图片描述(https://oscimg.o
Wesley13 Wesley13
4年前
MySQL 实战
项目七:各部门工资最高的员工(难度:中等)创建Employee 表,包含所有员工信息,每个员工有其对应的 Id,salary和departmentId。|Id|Name|Salary|DepartmentId|
贾蔷 贾蔷
6个月前
力扣1137题 解题思路和步骤 C++代码实现,力扣一共多少题
一、题目分析力扣1137题要求我们找到第N个泰波那契数。泰波那契数的定义是:T00,T11,T21,且在n0的条件下Tn3TnTn1Tn2。,当n4时,T4T3T2T14。这道题主要考查我们对递归或动态规划的理解和运用。在思考解题方法时,我们
贾蔷 贾蔷
5个月前
牛客13279题解:利用递归与深度优先搜索计算树的最大高度(附完整代码)
一、题目解读牛客13279题要求计算给定树的最大高度。题目输入一棵以邻接表形式表示的树(节点从0开始编号),需要输出从根节点到最深叶节点的最长路径长度。树的结构由n个节点和n1条边构成,保证为连通无环图。理解题目核心在于准确获取树的拓扑关系,并设计算法遍历