左神算法基础班3_13深度拷贝含有随机指针的链表

Problem:
  复制含有随机指针节点的链表
  【题目】 一种特殊的链表节点类描述如下:
  public class Node {
  public int value; public Node next; public
  Node rand;
  public Node(int data) { this.value = data; }
  }
  Node类中的value是节点值,next指针和正常单链表中next指针的意义
  一 样,都指向下一个节点,rand指针是Node类中新增的指针,这个指
  针可 能指向链表中的任意一个节点,也可能指向null。 给定一个由
  Node节点类型组成的无环单链表的头节点head,请实现一个 函数完成
  这个链表中所有结构的复制,并返回复制的新链表的头节点。 进阶:
  不使用额外的数据结构,只用有限几个变量,且在时间复杂度为 O(N)
  内完成原问题要实现的函数。

Solution :
  一:
    使用hash_map来进行存放原链表
    key=原链表, value=新建链表的节点
    然后根据原链表的结构将新链表进行结构构造
二:
    将原链表数组原地复制两份:
    head 1 2 3 4 5 6 NULL
    复制成: head head‘ 1 1‘ 2 2‘ 3 3‘ 4 4‘ 5 5‘ 6‘ 6‘ NULL
    然后Copy则取带‘的节点就行

  1 #pragma once
  2 #include <iostream>
  3 #include <hash_map>
  4
  5 using namespace std;
  6
  7 struct Node
  8 {
  9     int val;
 10     Node *rand;
 11     Node *next;
 12     Node(int a = -1) :val(a), rand(NULL), next(NULL) {}
 13 };
 14
 15
 16 Node* CopeListDeep(Node* head)
 17 {
 18     hash_map<Node*, Node*>map;
 19     Node* p = head;
 20     while (p)//新建链表的结构
 21     {
 22         map[p] = new Node(-1);
 23         p = p->next;
 24     }
 25
 26     p = head;
 27     while (p)//重构新链表的结构
 28     {
 29         map[p]->val = p->val;
 30         map[p]->next = map[p->next];
 31         map[p]->rand = map[p->rand];
 32         p = p->next;
 33     }
 34     return map[head];
 35 }
 36
 37 Node* CopeListDeep2(Node* head)
 38 {
 39     Node* cur = head;
 40     Node* next = NULL;
 41     while (cur)//将原链表复制两份
 42     {
 43         next = cur->next;
 44         cur->next = new Node(cur->val);
 45         cur->next->next = next;//此处为复制两份的代码
 46         cur = next;
 47     }
 48
 49     cur = head;
 50     Node* copyHead = NULL;//为了区分原链
 51     //先复制rand节点
 52     while (cur)//将新建的节点的结构进行重构
 53     {
 54         next = cur->next->next;//原链表的遍历
 55         copyHead = cur->next;
 56         copyHead->rand = ((cur->rand) == NULL ? NULL : (cur->rand)->next);
 57         cur = next;
 58     }
 59     //copyHead已经是链表的末尾NULL
 60     cur = head;
 61     Node* res = head->next;
 62     while (cur)
 63     {
 64         next = cur->next->next;
 65         copyHead = cur->next;
 66         cur->next = next;
 67         copyHead->next = (next == NULL) ? NULL : next->next;
 68         cur = next;
 69     }
 70
 71     //为什么不一次性将原链表进行还原和复制链表进行重构?
 72     //因为一旦原链表前半部分还原,而后半部分一旦有rand指向前半部分,原链表是能找到所指向
 73     //的节点,但由于前半部分原链表已经还原了,所以复制链表的rand无法依据原链表的位置找到自己rand所指向的节点,
 74     //故得先将rand  copy出来。
 75     return res;
 76
 77 }
 78
 79
 80 void Test()
 81 {
 82     Node *head = new Node(-1);
 83     head->next = new Node(1);
 84     head->next->next = new Node(2);
 85     head->next->next->next = new Node(3);
 86     head->next->next->next->next = new Node(4);
 87     head->next->next->next->next->next = new Node(5);
 88     head->next->next->next->next->next->next = new Node(6);
 89     head->next->next->next->next->next->next->next = NULL;
 90
 91
 92     head->rand = NULL;
 93     head->next->rand = head->next->next->next->next->next->next;
 94     head->next->next->rand = head->next->next->next->next->next->next;
 95     head->next->next->next->rand = head->next->next->next->next->next;
 96     head->next->next->next->next->rand = head->next->next->next;
 97     head->next->next->next->next->next->rand = NULL;
 98     head->next->next->next->next->next->next->rand = head->next->next->next->next;
 99
100
101     cout << "打印原链表:" << endl;
102     Node*p = head->next;
103     while (p)
104     {
105         cout << "next: " << p->val << "   rand: " << ((p->rand) ? p->rand->val : -1) << endl;
106         p = p->next;
107     }
108
109     cout << endl << "打印新链表:" << endl;
110     p = CopeListDeep2(head)->next;
111     while (p)
112     {
113         cout << "next: " << p->val << "   rand: " << ((p->rand) ? p->rand->val : -1) << endl;
114         p = p->next;
115     }
116
117
118 }

原文地址:https://www.cnblogs.com/zzw1024/p/10993026.html

时间: 2024-08-29 08:05:09

左神算法基础班3_13深度拷贝含有随机指针的链表的相关文章

九章算法面试题57 拷贝带随机指针的链表结构

九章算法官网-原文网址 http://www.jiuzhang.com/problem/57/ 题目 给出一条带随机指针的链表,对其进行深度拷贝(Deep Copy). 带随机指针的意思是,对于每个节点,除了next指针指向下一个节点以外,还带一个randomNext指针指向任何一个链表中的节点或空. 深度拷贝的意思是,对于新复制出来的链表,是一条完全独立于原来链表的链表,对于这个新的链表进行任何操作都不会对原来的链表产生影响. Follow Up Question: 如果不能使用额外的辅助空间

[LeetCode] Copy List with Random Pointer 拷贝带有随机指针的链表

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list. 这道链表的深度拷贝题的难点就在于如何处理随机指针的问题,由于每一个节点都有一个随机指针,这个指针可以为空,也可以指向链表的任意一个节点,如果我们在每生成一个新节点给其随机指

LeetCode138 Copy List with Random Pointer(深度复制带有随机指针的链表) Java题解

题目: A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list. 解题: 这题是要复制一个链表,这个链表比普通的链表多一个指针,这个指针可以指向任意地方,可以为空也可以为链表中的任一个节点,今天中午的时候我同学和我说起这题,当时问

左神算法进阶班1_5BFPRT算法

在无序数组中找到第k大的数1)分组,每N个数一组,(一般5个一组)2)每组分别进行排序,组间不排序3)将每个组的中位数拿出来,若偶数,则拿上 / 下中位数, 成立一个一个新数组.4)新数组递归调用BFPRT,则拿到整体的中位数num5)以num来划分整体数组,小于在左,大于在右边,使用[荷兰国旗方法]6)然后根据左右数组的规模,来确定进一步选择左右哪一部分:7)然后选择好后,继续 一:背景介绍在一大堆数中求其前k大或前k小的问题,简称TOP - K问题.而目前解决TOP - K问题最有效的算法即

左神算法进阶班3_1构造数组的MaxTree

题目 一个数组的MaxTree定义: 数组必须没有重复元素 MaxTree是一棵二叉树,数组的每一个值对应一个二叉树节点 包括MaxTree树在内且在其中的每一棵子树上,值最大的节点都是树的头 给定一个没有重复元素的数组arr,写出生成这个数组的MaxTree的函数,要求如果数组长度为N,则时间负责度为O(N).额外空间负责度为O(N). 实现思路 将数组按照大根堆进行排序 然后直接按照大根堆进行构造一颗二叉树即可. 使用单调栈 通过使用单调栈,将数组中中所有数的左右比他大的数记录下来 当某个数

左神算法进阶班5_1求二叉树中最大搜索子树大小

[题目] 给定一棵二叉树的头节点head,请返回最大搜索二叉子树的大小 [题解] 简化问题,想到该问题的解答应该有几种情形 第一种可能: 最大搜索二叉子树在head的左子树 第二种可能: 最大搜索二叉子树在head的右子树 第三种可能: 最大搜索二叉子树为自己:利用左子树的最大值与右子树的最小值 递归左子树,再递归右子树 信息1:左子树中最大搜索二叉树的大小 信息2:右子树中最大搜索二叉树的大小 信息3:左子树最大搜索二叉树的头结点 信息4:右子树最大搜索二叉树的头结点 信息5:左子树上的最大值

左神算法进阶班1_1添加最少字符得到原字符N次

Problem: 给定一个字符串str1,只能往str1的后面添加字符变成str2. 要求1:str2必须包含两个str1,两个str1可以有重合,但是不能以同一个位置开头. 要求2:str2尽量短最终返回str2 举例: str1 = 123,str2 = 123123 时,包含两个str1,且不以相同位置开头,且str2最短. str1 = 123123,str2 = 123123123 时,包含两个str1,且不以相同位置开头,且str2最短. str1 = 111,str2 = 1111

左神算法进阶班5_3求公司的最大活跃度

[题目] 一个公司的上下节关系是一棵多叉树,这个公司要举办晚会,你作为组织者已经摸清了大家的心理: 一个员工的直接上级如果到场,这个员工肯定不会来. 每个员工都有一个活跃度的值,决定谁来你会给这个员工发邀请函,怎么让舞会的气氛最活跃? 返回最大的活跃值. 举例: 给定一个矩阵来表述这种关系 matrix = { 1,6 1,5 1,4 } 这个矩阵的含义是: matrix[0] = { 1 , 6 },表示0这个员工的直接上级为1, 0这个员工自己的活跃度为6 matrix[1] = { 1 ,

左神算法进阶班6_1LFU缓存实现

[题目] LFU也是一个著名的缓存算法,自行了解之后实现LFU中的set 和 get 要求:两个方法的时间复杂度都为O(1) [题解] LFU算法与LRU算法很像 但LRU是最新使用的排在使用频率最前面,也就是LRU是通过使用时间进行排序, 使用时间越新,其使用频率越高,而使用时间越久,其使用频率越低,即当空间满时,被删除的概率最大 而LFU是根据使用次数来算使用频率的,使用次数越多,其使用频率越高,使用次数越少,使用频率越低,当空间满时越容易被删除 同样,使用hash_map表和双向链表进行存