《剑指offer》面试题26 复杂链表的复制 Java版
(定义一个新的数据结构,每个节点除了具有普通链表的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版的更多相关文章
- 剑指offer 面试题35.复杂链表的复制
时间O(N),空间O(N) /* struct RandomListNode { int label; struct RandomListNode *next, *random; RandomList ...
- 剑指offer面试题26-复杂链表的复制
题目: 请实现函数ComplexListNode* Clone(ComplexListNode* pHead).复制一个复杂链表. 在复杂链表中.每个节点除了一个m_pNext指针指向下一个节点外,另 ...
- 剑指Offer - 九度1524 - 复杂链表的复制
剑指Offer - 九度1524 - 复杂链表的复制2014-02-07 01:30 题目描述: 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点 ...
- 剑指Offer面试题:14.链表的倒数第k个节点
PS:这是一道出境率极高的题目,记得去年参加校园招聘时我看到了3次,但是每次写的都不完善. 一.题目:链表的倒数第k个节点 题目:输入一个链表,输出该链表中倒数第k个结点.为了符合大多数人的习惯,本题 ...
- 剑指offer——27. 二叉搜索树与双向链表(Java版)
题目: 剑指offer的题目有挺多都挺典型的,就像这一道.不过书中的代码写的真是ugly,有很多题目LeetCode上都有,可以去LeetCode讨论区看看,经常有一些大神分享,写的代码真是高效.简洁 ...
- 剑指offer面试题26:复杂链表的复制
题目:请实现一个函数,复制一个复杂链表. 在复杂链表中,每个结点除了有一个next指针指向下一个结点外,还有一个sibling指针指向链表中的任意结点或者nulL 直观解法: 1.遍历链表,复制链表节 ...
- 剑指Offer:面试题26——复制复杂的链表(java实现)
问题描述: 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点). 思路1: 1.先复制链表节点,并用next链接起来. 2.然后对每一个结点去修改 ...
- 剑指Offer:面试题16——反转链表(java实现)
问题描述 定义一个函数,输入一个链表的头结点,反转该链表并输出反转后的链表的头结点.链表结点如下: public class ListNode { int val; ListNode next = n ...
- 【剑指offer 面试题15】链表中倒数第K个结点
思路: 定义两个指针同时指向head,第一个指针先走K-1步,随后二个指针同时移动,当第一个指针到末尾处时,第二个指针所指向的即为倒数第K个结点. #include <iostream> ...
随机推荐
- win10激活方法 windows 10 最简单的激活方法
1.首先,要用管理员权限打开cmd命令行窗口,可以搜索框中输入“cmd”,在出现的“命令行提示符”,图标上右击“以管理员身份运行”. 2.为了让其它激活工具的密钥清除,先卸载密钥,在命令行输入 ...
- 读取xml文件中的配置参数实例_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 paras.xml文件 <?xml version="1.0" encoding=" ...
- 【NOIP2014模拟11.3】蛋糕
题目 今天是Bessie的生日,他买了一个蛋糕和朋友们一起分享,蛋糕可以看成是一个R行C列的表格,共有R*C个格子,每个格子都有一个0至9的数字,表示该格子蛋糕拥有的巧克力.现在Bessie要把蛋糕横 ...
- spark2.1.0 自定义AccumulatorV2累加少值(线程不安全)?
一.踩坑经历 自定义的accumulator是线程不安全的,会造成累加结果不正确.自定找了很久没想到是线程不安全行成的. 二.解决方法 创建一个线程安全的集合变量(我用的是Java的Concurren ...
- ETL工具之——kettle使用简介
ETL工具之——kettle使用简介 https://yq.aliyun.com/articles/157977?spm=5176.10695662.1996646101.searchclickres ...
- HTTS TTLS 433
HTTP和HTTPS协议,看一篇就够了 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/x ...
- Android图片优化指南
图片作为内存消耗大户,一直是开发人员尝试优化的重点对象.Bitmap的内存从3.0以前的位于native,到后来改成jvm,再到8.0又改回到native.fresco花费很多精力在5.0系统之前把B ...
- html address标签 语法
html address标签 语法 作用:定义文档作者/所有者的联系信息. 说明:如果 <address> 元素位于 <body> 元素内部,则它表示该文档作者/所有者的联系信 ...
- #418 Div2 Problem B An express train to reveries (构造 || 全排列序列特性)
题目链接:http://codeforces.com/contest/814/problem/B 题意 : 有一个给出两个含有 n 个数的序列 a 和 b, 这两个序列和(1~n)的其中一个全排列序列 ...
- Overview over available Turtle and Screen methods
24.5.2.1. Turtle methods Turtle motion Move and draw forward() | fd() backward() | bk() | back() rig ...