9.15 BFS中等 133 Clone Graph review 138 随机链表的复制

133 Clone Graph

cpp 复制代码
//错误代码

class Solution {
public:
    Node* cloneGraph(Node* node) {
        //邻接表、BFS---》类似于二叉树的层次遍历
        if(!node || !node->val) return node;
        //构造队列
        queue<Node*> prev;
        prev.push(node);
        //构造新的图结点列表
        vector<Node*> adjList;
        //辅助数组
        // 哈希集合用于记录访问过的节点
        unordered_set<Node*> visited;
        visited.insert(node);
        while(prev.empty()){
            //获取结点并出栈
            Node* newNode = new Node();
            Node* curr = prev.front();prev.pop();

            newNode->val = curr->val;
            for(Node* neighbor : curr->neighbors){
                //复制对应的邻接点
                newNode->neighbors.push_back(neighbor);
                // 如果邻居没有被访问过
                if (visited.find(neighbor) == visited.end()) {
                    prev.push(neighbor);         // 将未访问的邻居加入队列
                    visited.insert(neighbor); // 标记为已访问
                }
            }
            adjList.push_back(newNode);
        }
        return adjList[0];
    }
};)
  • 在克隆图的过程中,直接使用了原图中的邻居列表(newNode->neighbors.push_back(neighbor)),而没有克隆邻居节点的副本。实际上,需要复制整个图中的节点及其连接关系 ,因此应为每个节点创建新的副本,而不是直接使用原图的邻居节点
  • 图的克隆和链表的复制(特别是带随机指针的链表的深度复制138) 很类似。两者都涉及节点的复制,并且不仅仅是单独复制节点本身,还必须考虑其邻接点或其他关联节点(例如,图的邻居节点或链表的随机指针)。
cpp 复制代码
/*
// 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 nullptr;
        //原结点-->克隆结点
        unordered_map<Node* , Node*> cloneNodes;
        //BFS
        queue<Node*> prev;
        prev.push(node);
        //第一个克隆结点
        cloneNodes[node] = new Node(node->val);

        while(!prev.empty()){
            Node* curr = prev.front();
            prev.pop();

            for(Node* neighbor : curr->neighbors){
                //如果邻居结点还没有被克隆
                if(cloneNodes.find(neighbor) == cloneNodes.end()){
                    cloneNodes[neighbor] = new Node(neighbor->val);
                    //加入队列
                    prev.push(neighbor);
                }
                //将克隆的邻居节点加入当前克隆节点的邻接表
                cloneNodes[curr]->neighbors.push_back(cloneNodes[neighbor]);
            }
        }
        return cloneNodes[node];

    }
};

138 随机链表的复制

cpp 复制代码
/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(!head) return nullptr;
        //建立新链表
        Node* p = head;             //p是原链表指针
        Node* dum = new Node(0);
        Node* temp = dum;           //temp是新链表指针

        //构造哈希表
        unordered_map<Node* , Node*> copyList;
        //第一次遍历原链表,复制next指针
        while(p){
            Node* node = new Node(p->val);
            temp->next = node;

            copyList[p] = node;

            temp = temp->next;
            p = p->next;
        }
        //第二次遍历原链表,复制random
        p = head;
        temp = dum->next;
        while(p){
            if(p->random != nullptr){
                temp->random = copyList[p->random];
            }
            temp = temp->next;
            p = p->next;
        }
        return dum->next;


    }
};

summary 哈希表与克隆:用于存储原节点和新节点的映射

1. 防止重复克隆

当我们遍历图或链表时,如果不使用哈希表,就可能会多次创建同一个节点的副本,从而浪费内存和时间。哈希表通过记录原节点和对应的新节点,确保每个节点只会被克隆一次。每当需要访问一个节点的邻居(在图中)或者 nextrandom(在链表中)时,哈希表可以直接提供已克隆的节点,而无需重复创建。

2. 保证边的复制

当你遍历一个节点时,你不仅需要复制该节点,还需要复制它所有的边(即图中的邻接点或者链表中的指针)。这里哈希表起到了关键作用:

  • 对于图的克隆,当你克隆一个节点时,它的邻居节点可能已经被克隆,也可能还没有。如果没有克隆,哈希表会创建并存储这个邻居节点的克隆版;如果已经克隆,你可以通过哈希表找到对应的克隆节点,并将它加入当前节点的邻接表中,确保边的复制。


  • 对于链表,类似地,你需要通过哈希表将 randomnext 指针正确指向克隆后的节点,而不是指向原链表中的节点。


3. 流程示例

以图为例,当我们遍历到一个节点 ( A ) 时,如果节点 ( A ) 的邻居 ( B ) 还未被克隆,哈希表就会克隆 ( B ) 并将其存储。接下来,无论你何时再次遇到 ( B ),都可以直接从哈希表中获取克隆节点。这样,边 ( A - B ) 也就得以正确复制。

直观的解释:

通过哈希表的存储和查找机制,可以保证每次访问节点时,邻居的指向都是已经克隆的副本,而不是原图中的节点,从而保证边(指针)的完整性

相关推荐
Forever Nore7 分钟前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考2 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX2 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面3 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号3 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽3 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI4 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者5 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者5 小时前
【征程6】校准量化中HistogramObserver解析
算法
OuO-26 小时前
笔试强训 Day 34:ISBN 号码、kotori 和迷宫、矩阵最长递增路径
java·算法·矩阵