(定义一个新的数据结构,每个节点除了具有普通链表的next域外,还有一个额外的引用指向任意节点。我们要对由该特殊数据结构形成的链表进行复制。)

我的方法:也就是克隆一个这种特殊链表,很快想到先不考虑原链表sibling域,复制出一个新的链表,然后再去给sibling域赋值。由于sibling可以指向任何节点,而且我们是根据原链表的sibling来确定新链表中的sibling,所以每次我们寻找新链表中某个节点的sibling,都要两个指针重新从头开始扫描以确定新链表中的sibling。所以时间复杂度是O(n)+O(n^2)。

    	public ComplexListNode complexClone(ComplexListNode head){
if(head == null)return null;
ComplexListNode headMark = head;
ComplexListNode newHeadMark = new ComplexListNode(head.val);
ComplexListNode newHead = newHeadMark;
head = head.next; //仅形成next域
for(; head != null; head = head.next){
newHead.next = new ComplexListNode(head.val);
newHead = newHead.next;
}
//形成sibling域
head = headMark;
newHead = newHeadMark;
for(; head!=null; head=head.next, newHead=newHead.next){
ComplexListNode index = headMark;
ComplexListNode newIndex = newHeadMark;
for(; index!=null; index=index.next,newIndex=newIndex.next){
if(head.sibling == index){
newHead.sibling = newIndex;
}
}
}
return newHeadMark;
}

书中方法一:一看书,果然上面的方法是最烂的,主要时间复杂度集中在第二步确定sibling上面,我们是否能够让每次寻找的时间复杂度减小到O(1)?一般来说牺牲空间复杂度可以降低时间复杂度+一次寻找的时间复杂度是O(1),我们就想到了HashMap。如何使用呢?我们在创建新链表的时候存储原链表每个节点对应的新链表节点,如(old,new),这样在第二步连接sibling的时候就可以根据原链表节点一步找到新链表节点。

    	public ComplexListNode complexClone2(ComplexListNode head){
if(head == null)return null;
Map<ComplexListNode, ComplexListNode> map = new HashMap<>();
ComplexListNode headMark = head;
ComplexListNode newHeadMark = new ComplexListNode(head.val);
ComplexListNode newHead = newHeadMark;
map.put(headMark, newHead); head = head.next;
for(; head!=null; head = head.next){
newHead.next = new ComplexListNode(head.val);
map.put(head, newHead.next);
newHead = newHead.next;
}
for(ComplexListNode index = headMark,newIndex = newHeadMark;
index!=null; index=index.next, newIndex=newIndex.next){
newIndex.sibling = map.get(index.sibling);
}
return newHeadMark;
}

书中方法二:书上还讲了一种时间复杂度O(n)空间复杂度O(1)的方法。我们既可以根据原链表的节点迅速确定新链表的节点(即和HashMap一样也存在一种一一对应的关系),又不用额外创建空间。创建新链表时,把新链表的对应节点放在原链表节点的后面可以达到一一对应的效果,最后我们把一整条链表拆开,这样也不会破坏源链表结构,也得到了新链表。从本质上来讲,如果我们完全抛弃原链表的结构去寻找sibling,相当于丢弃了一部分信息,也就是把所有节点当成一个set去遍历寻找。如果考虑了sibling的结构(即把新的节点创建在原节点之后),相当于走了捷径。

    	public ComplexListNode complexClone3(ComplexListNode head){
copyAndConstruct(head);
linkSibling(head);
return unpackage(head);
}
private void copyAndConstruct(ComplexListNode head){
ComplexListNode index = head;
while(index != null){
ComplexListNode temp = new ComplexListNode(index.val);
temp.next = index.next;
index.next = temp;
index = index.next.next;
}
}
private void linkSibling(ComplexListNode head){
ComplexListNode index = head;
while(index != null){
if(index.sibling == null){
index.next.sibling = null;
}else{
index.next.sibling = index.sibling.next;
}
index = index.next.next;
}
} private ComplexListNode unpackage(ComplexListNode head){
if(head == null)return null;
ComplexListNode newIndex = head.next;
ComplexListNode newHead = newIndex;
ComplexListNode index = head;
while(index != null){
index.next = newIndex.next;
if(newIndex.next != null){
newIndex.next = newIndex.next.next;
}
index = index.next;
newIndex = newIndex.next;
}
return newHead;
}

《剑指offer》面试题26 复杂链表的复制 Java版的更多相关文章

  1. 剑指offer 面试题35.复杂链表的复制

    时间O(N),空间O(N) /* struct RandomListNode { int label; struct RandomListNode *next, *random; RandomList ...

  2. 剑指offer面试题26-复杂链表的复制

    题目: 请实现函数ComplexListNode* Clone(ComplexListNode* pHead).复制一个复杂链表. 在复杂链表中.每个节点除了一个m_pNext指针指向下一个节点外,另 ...

  3. 剑指Offer - 九度1524 - 复杂链表的复制

    剑指Offer - 九度1524 - 复杂链表的复制2014-02-07 01:30 题目描述: 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点 ...

  4. 剑指Offer面试题:14.链表的倒数第k个节点

    PS:这是一道出境率极高的题目,记得去年参加校园招聘时我看到了3次,但是每次写的都不完善. 一.题目:链表的倒数第k个节点 题目:输入一个链表,输出该链表中倒数第k个结点.为了符合大多数人的习惯,本题 ...

  5. 剑指offer——27. 二叉搜索树与双向链表(Java版)

    题目: 剑指offer的题目有挺多都挺典型的,就像这一道.不过书中的代码写的真是ugly,有很多题目LeetCode上都有,可以去LeetCode讨论区看看,经常有一些大神分享,写的代码真是高效.简洁 ...

  6. 剑指offer面试题26:复杂链表的复制

    题目:请实现一个函数,复制一个复杂链表. 在复杂链表中,每个结点除了有一个next指针指向下一个结点外,还有一个sibling指针指向链表中的任意结点或者nulL 直观解法: 1.遍历链表,复制链表节 ...

  7. 剑指Offer:面试题26——复制复杂的链表(java实现)

    问题描述: 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点). 思路1: 1.先复制链表节点,并用next链接起来. 2.然后对每一个结点去修改 ...

  8. 剑指Offer:面试题16——反转链表(java实现)

    问题描述 定义一个函数,输入一个链表的头结点,反转该链表并输出反转后的链表的头结点.链表结点如下: public class ListNode { int val; ListNode next = n ...

  9. 【剑指offer 面试题15】链表中倒数第K个结点

    思路: 定义两个指针同时指向head,第一个指针先走K-1步,随后二个指针同时移动,当第一个指针到末尾处时,第二个指针所指向的即为倒数第K个结点. #include <iostream> ...

随机推荐

  1. jvm——CMS 垃圾回收器(未完)

    https://matt33.com/2018/07/28/jvm-cms/ 阶段1:Initial Mark stop-the-wolrd 标记那些直接被 GC root 引用或者被年轻代存活对象所 ...

  2. sudo: pip:command not found问题解决

    python3 sudo apt-get install python3-pip python2 sudo apt-get install python-pip如果还是不行,则按照下面操作 原因:编译 ...

  3. vue项目中监听sessionStorage值发生变化

    首先在main.js中给Vue.protorype注册一个全局方法, 其中,我们约定好了想要监听的sessionStorage的key值为’watchStorage’, 然后创建一个StorageEv ...

  4. 使用vscode打断点

    1.vscode打开的文件必须只包含你要调适的项目,不能同时在一个vscode打开多个项目窗口 2.点击vscode的这个小蜘蛛 3.选择添加配置 4.此时自动生成了一个文件,launch.json: ...

  5. mac 绑定阿里企业邮箱

    注意事项: 1. 收件服务器 千万得写对, 选 pop 就写 pop.mxhichina.com; 选 imap 就写 imap.mxhichina.com 2. 发件服务器 必须写,smtp.mxc ...

  6. Spring Boot教程(十)异步方法测试

    测试 测试代码如下: @Component public class AppRunner implements CommandLineRunner { private static final Log ...

  7. 通过构造器配置Bean

    public class Role { private Log id; private String roleName; private String note; public Role(String ...

  8. Python 使用Qt进行开发(三)

    下面我们实现日期时间框的添加,表示日期时间的文本框可以使用QtWidgets控件下的 QDateEdit() , QTimeEdit() , QDateTime() 三个方法实现. 1,使用QDate ...

  9. hook工具

    调试工具 WinDbg com/daoyuly/p/3570037 DebugDiag procexp64.exe APIMonitor OllyDBG API伴侣 FileMon  v7.04  ( ...

  10. Spring 初识

    一.Spring是什么? 首先可以进入Spring官网 https://spring.io/ 看一下相关介绍. Spring为开发者提供了一站式的轻量级应用开发平台.简单来说,Spring为开发者提供 ...