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 ) 也就得以正确复制。

直观的解释:

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

相关推荐
Lenyiin14 分钟前
01.02、判定是否互为字符重排
算法·leetcode
鸽鸽程序猿29 分钟前
【算法】【优选算法】宽搜(BFS)中队列的使用
算法·宽度优先·队列
Jackey_Song_Odd30 分钟前
C语言 单向链表反转问题
c语言·数据结构·算法·链表
Watermelo61733 分钟前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
乐之者v39 分钟前
leetCode43.字符串相乘
java·数据结构·算法
A懿轩A2 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
古希腊掌管学习的神2 小时前
[搜广推]王树森推荐系统——矩阵补充&最近邻查找
python·算法·机器学习·矩阵
云边有个稻草人2 小时前
【优选算法】—复写零(双指针算法)
笔记·算法·双指针算法
半盏茶香2 小时前
在21世纪的我用C语言探寻世界本质 ——编译和链接(编译环境和运行环境)
c语言·开发语言·c++·算法
忘梓.3 小时前
解锁动态规划的奥秘:从零到精通的创新思维解析(3)
算法·动态规划