Little-Prince

导航

133. 克隆图

133. 克隆图

给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。
图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。
class Node {
    public int val;
    public List<Node> neighbors;
}
 
测试用例格式:
简单起见,每个节点的值都和它的索引相同。例如,第一个节点值为 1(val = 1),第二个节点值为 2(val = 2),以此类推。该图在测试用例中使用邻接列表表示。
邻接列表 是用于表示有限图的无序列表的集合。每个列表都描述了图中节点的邻居集。
给定节点将始终是图中的第一个节点(值为 1)。你必须将 给定节点的拷贝 作为对克隆图的引用返回。
 
 
输入:adjList = [[2,4],[1,3],[2,4],[1,3]]
输出:[[2,4],[1,3],[2,4],[1,3]]
解释:
图中有 4 个节点。
节点 1 的值是 1,它有两个邻居:节点 2 和 4 。
节点 2 的值是 2,它有两个邻居:节点 1 和 3 。
节点 3 的值是 3,它有两个邻居:节点 2 和 4 。
节点 4 的值是 4,它有两个邻居:节点 1 和 3 。
 
 
输入:adjList = [[]]
输出:[[]]
解释:输入包含一个空列表。该图仅仅只有一个值为 1 的节点,它没有任何邻居。

 输入:adjList = []
输出:[]
解释:这个图是空的,它不含任何节点。

 

 
提示:
 节点数不超过 100 。
 每个节点值 Node.val 都是唯一的,1 <= Node.val <= 100。
 无向图是一个简单图,这意味着图中没有重复的边,也没有自环。
 由于图是无向的,如果节点 p 是节点 q 的邻居,那么节点 q 也必须是节点 p 的邻居。
 图是连通图,你可以从给定节点访问到所有节点。
 
思路:
方法一:深度优先搜索 DFS 沿给定节点的邻居节点一直搜索到最后。
1.从给定节点开始遍历图。
2.使用一个 HashMap 存储所有已被访问和复制的节点。HashMap 中的 key 是原始图中的节点,value 是克隆图中的对应节点。如果某个节点已经被访问过,则返回其克隆图中的对应节点。
3.如果当前访问的节点不在 HashMap 中,则创建它的克隆节点存储在 HashMap 中。注意:在进入递归之前,必须先创建克隆节点并保存在 HashMap 中。
 
 
时间复杂度 o(n), 空间复杂度 o(n)
 
代码:
/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> neighbors;
    
    Node() {
        val = 0;
        neighbors = vector<Node*>();
    }
    
    Node(int _val) {
        val = _val;
        neighbors = vector<Node*>();
    }
    
    Node(int _val, vector<Node*> _neighbors) {
        val = _val;
        neighbors = _neighbors;
    }
};
*/

class Solution {
    unordered_map<Node*, Node*> visited;
public:
    Node* cloneGraph(Node* node) {
        if(!node)
            return node;       
         unordered_map<Node*, Node*>::iterator it = visited.find(node); 
         if(it!=visited.end())
            return it->second;
        Node *new_node;
        new_node = new Node(node->val);
        visited[node] = new_node;
        int i, len = node->neighbors.size();
        for(i = 0; i < len; i++)
        {
            new_node->neighbors.push_back(cloneGraph(node->neighbors[i]));
        }

        return new_node;
        
    }

   
};

 

思路:用栈迭代实现 DFS

1.从给定节点开始遍历图,创建该节点对应的新节点,并将该节点压入栈中。
2.使用一个 HashMap 存储所有已被访问和复制的节点。HashMap 中的 key 是原始图中的节点,value 是克隆图中的对应节点。如果某个节点 A 的邻节点已经被访问过,将该邻接点加入 A 的邻接表中。如果 A 的所有邻节点都被访问过,将 A 从栈中弹出。
3.如果当前访问的节点A 的邻节点不在 HashMap 中,则创建它的克隆节点存储在 HashMap 中,并将该节点压入栈中,同时清空 A 的邻节点。
 
代码:
 
/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> neighbors;
    
    Node() {
        val = 0;
        neighbors = vector<Node*>();
    }
    
    Node(int _val) {
        val = _val;
        neighbors = vector<Node*>();
    }
    
    Node(int _val, vector<Node*> _neighbors) {
        val = _val;
        neighbors = _neighbors;
    }
};
*/

class Solution {
public:
    Node* cloneGraph(Node* node) {
        unordered_map<Node*, Node*> visited;
        stack<Node*> st;
        if(!node)
            return node;
        Node *new_node, *old_node;
        Node *old_node1, *new_node1;
        new_node = new Node(node->val);
        visited[node] = new_node;
        st.push(node);
        int i, len, flag = 1;
        while(!st.empty())
        {
            old_node = st.top();
            len = old_node->neighbors.size();
            new_node = visited[old_node];
            unordered_map<Node*, Node*>::iterator it;
            flag = 1;
            for(i = 0; i< len; i++)
            {
                old_node1 = old_node->neighbors[i];
                it = visited.find(old_node1);
                if(it!=visited.end())
                {
                        new_node->neighbors.push_back(it->second);
                }
                else
                {
                    new_node1 = new Node(old_node1->val);
                    visited[old_node1] = new_node1;
                    st.push(old_node1);
                    flag = 0;
                    break;
                }
            }
            if(flag)
            {
                st.pop();
            }
            else
            {
                new_node->neighbors.clear();
            }          
        }
        return visited[node];

    }
};
/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> neighbors;
    
    Node() {
        val = 0;
        neighbors = vector<Node*>();
    }
    
    Node(int _val) {
        val = _val;
        neighbors = vector<Node*>();
    }
    
    Node(int _val, vector<Node*> _neighbors) {
        val = _val;
        neighbors = _neighbors;
    }
};
*/

class Solution {
   
public:
    Node* cloneGraph(Node* node) {
        if(!node)
            return node;
        unordered_map<Node*, Node*> visited;       
       
        Node *new_node, *old_node, *head;
        stack<Node*> deal;
        new_node = new Node(node->val);
        visited[node] = new_node;
        deal.push(node);
        head = new_node;
        int i, len;
        while(!deal.empty())
        {
            old_node = deal.top();
            deal.pop();
            len = old_node->neighbors.size();
            unordered_map<Node*, Node*>::iterator it = visited.find(old_node); 
            new_node = it->second;
            for(i = 0; i < len; i++)
           {
              new_node->neighbors.push_back(copy(old_node->neighbors[i], visited, deal));
           }
         
               
        }
       
    
        return head;
        
    }


   Node *copy(Node *old_node1, unordered_map<Node*,Node*>&visited, stack<Node*>&deal)
   {
       unordered_map<Node*, Node*>::iterator it = visited.find(old_node1); 
            if(it!=visited.end())
                return it->second;
            else
            {
               Node *new_node1;
               new_node1 = new Node(old_node1->val);
               visited[old_node1] = new_node1;
               deal.push(old_node1);
               return new_node1;
            }
   }
};

 

 

思路:广度优先遍历 BFS 利用队列

使用 HashMap 存储所有访问过的节点和克隆节点。HashMap 的 key 存储原始图的节点,value 存储克隆图中的对应节点。visited 用于防止陷入死循环,和获得克隆图的节点。

将第一个节点添加到队列。克隆第一个节点添加到名为 visited 的 HashMap 中。

BFS 遍历
从队列首部取出一个节点。
遍历该节点的所有邻接点。
如果某个邻接点已被访问,则该邻接点一定在 visited 中,那么从 visited 获得该邻接点。
否则,创建一个新的节点存储在 visited 中。并将该节点加入队列。
将克隆的邻接点添加到克隆图对应节点的邻接表中。
 
时间复杂度 o(n), 空间复杂度o(n)
 
代码
/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> neighbors;
    
    Node() {
        val = 0;
        neighbors = vector<Node*>();
    }
    
    Node(int _val) {
        val = _val;
        neighbors = vector<Node*>();
    }
    
    Node(int _val, vector<Node*> _neighbors) {
        val = _val;
        neighbors = _neighbors;
    }
};
*/

class Solution {
   
public:
    Node* cloneGraph(Node* node) {
        if(!node)
            return node;
        unordered_map<Node*, Node*> visited;       
       
        Node *new_node, *old_node, *head;
        queue<Node*> deal;
        new_node = new Node(node->val);
        visited[node] = new_node;
        deal.push(node);
        head = new_node;
        int i, len;
        while(!deal.empty())
        {
            old_node = deal.front();
            deal.pop();
            len = old_node->neighbors.size();
            unordered_map<Node*, Node*>::iterator it = visited.find(old_node); 
            new_node = it->second;
            for(i = 0; i < len; i++)
           {
              new_node->neighbors.push_back(copy(old_node->neighbors[i], visited, deal));
           }
               
        }
       
    
        return head;
        
    }

   Node *copy(Node *old_node1, unordered_map<Node*,Node*>&visited, queue<Node*>&deal)
   {
       unordered_map<Node*, Node*>::iterator it = visited.find(old_node1); 
            if(it!=visited.end())
                return it->second;
            else
            {
               Node *new_node1;
               new_node1 = new Node(old_node1->val);
               visited[old_node1] = new_node1;
               deal.push(old_node1);
               return new_node1;
            }
   }
};

 

 
 
 

posted on 2020-08-02 00:57  Little-Prince  阅读(143)  评论(0编辑  收藏  举报