IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 复杂链表的复制 -> 正文阅读

[数据结构与算法]复杂链表的复制

? ?对应letecode链接:

力扣

题目描述:

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

示例 1:

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:

输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 3:

输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
示例 4:

输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。

提示:

-10000 <= Node.val <= 10000
Node.random?为空(null)或指向链表中的节点。
节点数目不超过 1000 。?

方法1:哈希表

创建哈希表保存已拷贝结点,格式?{原结点:拷贝结点}

8.jpg

第二步我们再遍历原链表,这次我们要将新链表的next和random指针给链接好

9.jpg

从上图中我们可以发现,原节点和新节点是一一对应的关系,所以

hash(原节点),得到的就是对应的新节点
hash(原节点->next),得到的就是对应的新节点->next
hash(原节点->random),得到的就是对应的新节点->random
所以,我们只需要再次遍历原链表,然后设置:
新节点->next -> hash[原节点->next]
新节点.random -> hash[原节点->random]
这样新链表的next和random都被串联起来了
最后,我们然后我们返回hash[head],也就是对应的新链表的头节点,就可以解决此问题了。

对应代码:

class Solution {
public:
    Node* copyRandomList(Node* head) {
        Node*cur=head;
        unordered_map<Node*,Node*>hash;//创建哈希表
        while(cur){
            hash.insert(make_pair(cur,new Node(cur->val)));//复制节点
            cur=cur->next;
        }
        cur=head;//复制节点的指向
        while(cur){
            hash[cur]->next=hash[cur->next];//新结点next指向同旧结点的next指向
            hash[cur]->random=hash[cur->random];///新结点random指向同旧结点的random指向
            cur=cur->next;//迭代往后走
        }
        return hash[head];//返回复制后的节点
    }
};

?方法二:迭代

个人认为这道题最大的难度就在于复制链表中的随机节点

4.jpg

比如说上面这个图中

1.节点值为1的random指向的是节点3

2.节点值为2的random指向空

3.节点值为3的random指向的是1.??

复制的链表和原链表没有任何的链接关系这使得我们很难去复制节点。但是我们可以让原链表和新链表建立链接关系?

根据遍历到的原节点创建对应的新节点,每个新创建的节点是在原节点后面,比如下图中原节点1不再指向原节点2,而是指向新节点1

5.jpg

第二步是最关键的一步,用来设置新链表的随机指针?

6.jpg

上图中,我们可以观察到这么一个规律

原节点1的随机指针指向原节点3,新节点1的随机指针指向的是原节点3的next
原节点3的随机指针指向原节点2,新节点3的随机指针指向的是原节点2的next
也就是,原节点i的随机指针(如果有的话),指向的是原节点j
那么新节点i的随机指针,指向的是原节点j的next

第三步就简单了,只要将两个链表分离开,再返回新链表就可以了

7.jpg

对应代码:

class Solution {
public:
    Node* copyRandomList(Node* head) {
          Node*cur=head;
          //链接节点
          while(cur){
              Node*copyNode=new Node(cur->val);
              Node*next=cur->next;//保存下一个
              cur->next=copyNode;
              copyNode->next=next;
              cur=next;
          }
          //链接拷贝节点中的random
          cur=head;
          while(cur){
              Node*copyNode=cur->next;
              if(cur->random==nullptr){//如果原节点中的random指向空那么我也指向空
                     copyNode->random=nullptr;
              }
              else{
                  copyNode->random=cur->random->next;//拷贝节点的random等于原节点random的next
              }
                     cur=copyNode->next;//迭代往后走
          }
              cur=head;
              Node*copyHead=new Node(-1);
              Node*ans=copyHead;
          while(cur){
            Node*copyNode=cur->next;//保存拷贝节点
            Node*next=copyNode->next;//保存原节点的下一个
            cur->next=next;//链接
            copyHead->next=copyNode;
            copyHead=copyHead->next;
            cur=next;//迭代往后走;
          }
          return ans->next;

    }
};

扁平化多级双向链表

对应letecode链接:

430. 扁平化多级双向链表 - 力扣(LeetCode) (leetcode-cn.com)

题目描述:

多级双向链表中,除了指向下一个节点和前一个节点指针之外,它还有一个子链表指针,可能指向单独的双向链表。这些子列表也可能会有一个或多个自己的子项,依此类推,生成多级数据结构,如下面的示例所示。

给你位于列表第一级的头节点,请你扁平化列表,使所有结点出现在单级双链表中。

示例 1:

输入:head = [1,2,3,4,5,6,null,null,null,7,8,9,10,null,null,11,12]
输出:[1,2,3,7,8,11,12,9,10,4,5,6]
解释:

输入的多级列表如下图所示:

扁平化后的链表如下图:


示例 2:

输入:head = [1,2,null,3]
输出:[1,3,2]
解释:

输入的多级列表如下图所示:

? 1---2---NULL
? |
? 3---NULL
示例 3:

输入:head = []
输出:[]

如何表示测试用例中的多级链表?

以 示例 1 为例:

?1---2---3---4---5---6--NULL
? ? ? ? ?|
? ? ? ? ?7---8---9---10--NULL
? ? ? ? ? ? ?|
? ? ? ? ? ? ?11--12--NULL
序列化其中的每一级之后:

[1,2,3,4,5,6,null]
[7,8,9,10,null]
[11,12,null]
为了将每一级都序列化到一起,我们需要每一级中添加值为 null 的元素,以表示没有节点连接到上一级的上级节点。

[1,2,3,4,5,6,null]
[null,null,7,8,9,10,null]
[null,11,12,null]
合并所有序列化结果,并去除末尾的 null 。

[1,2,3,4,5,6,null,null,null,7,8,9,10,null,null,11,12]

提示:

节点数目不超过 1000
1 <= Node.val <= 10^5

迭代:

首先扁平化第一层和第一层的孩子节点得到新的链表
对新的链表进行两层链表的扁平化,直到是单级双链表

class Solution {
public:
    Node* flatten(Node* head) {
        Node*cur=head;
        while(cur){
             Node*next=cur->next;//保存下一个
            if(cur->child){
                Node*child=cur->child;
                cur->next=child;//插入到当前节点的后面
                child->prev=cur;
                cur->child=nullptr;
                while(child&&child->next){
                    child=child->next;//一直遍历到最后一个元素
                }
                child->next=next;//链接
                if(next!=nullptr){
                    next->prev=child;//链接
                }
            }
           cur=cur->next;//迭代往后走
        }
        return head;
    }
};

使用栈:

class Solution {
public:
    Node* flatten(Node* head) {
        if(head==NULL) return nullptr;
        Node* newhead = new Node();
        stack<Node*> st;
        st.push(head);
        while(!st.empty()){
            Node* temp = st.top();
            st.pop();
            newhead->next = temp;
            temp->prev = newhead;
            newhead = temp;
            if(temp->next!=NULL){
                st.push(temp->next);
            }
            if(temp->child!=NULL){
                st.push(temp->child);   
                temp->child=NULL;
            }
        }
        head->prev=NULL;
        return head;
    }
};
class Solution {
public:
    Node* flatten(Node* head) {
        Node* node = head;
        stack<Node*> s;
        while(node != nullptr) {
            // 孩子不为空
            if(node -> child != nullptr) {
                if(node -> next != nullptr) {
                    s.push(node -> next);
                }
                Node* child = node -> child;
                // 扁平化
                node -> next = child;
                child -> prev = node;
                // 孩子要去掉
                node -> child = nullptr;
            }
            if(node -> next == nullptr && !s.empty()) {
                Node* next = s.top();
                s.pop();
                node -> next = next;
                next -> prev = node;
            }
            node = node -> next;
        }
        return head;
    }
};

由于马上要考试了后期来补解释

?

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-12-14 16:12:59  更:2021-12-14 16:13:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 16:58:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码