【剑指Offer学习】【面试题26:复杂链表的复制】
题目:请实现函数ComplexListNode clone(ComplexListNode head),复制一个复杂链表。
在复杂链表中,每一个结点除了有一个next 域指向下一个结点外,另一个sibling 指向链表中的随意结点或者null。
结点结构定义:
public static class ComplexListNode {
int value;
ComplexListNode next;
ComplexListNode sibling;
}
解题思路:
图4.8 是一个含有5 个结点的复杂链表。图中实线箭头表示next 指针,虚线箭头表示sibling 指针。为简单起见。指向null 的指针没有画出。
在不用辅助空间的情况下实现O(n)的时间效率。
第一步:仍然是依据原始链表的每一个结点N 创建相应的N’。
把N’链接在N的后面。图4.8 的链表经过这一步之后的结构,如图4.9 所看到的。
第二步:设置复制出来的结点的sibling。
假设原始链表上的N的sibling指向结点S,那么其相应复制出来的N’是N的pext指向的结点,相同S’也是S的next指向的结点。设置sibling之后的链表如图4.10 所看到的。
第三步:把这个长链表拆分成两个链表。把奇数位置的结点用next .
链接起来就是原始链表,把偶数位置的结点用next 链接起来就是复制
出来的链表。图4. 10 中的链表拆分之后的两个链表如图4.11 所看到的。
代码实现:
public class Test26 {
/**
* 复杂链表结点
*/
public static class ComplexListNode {
int value;
ComplexListNode next;
ComplexListNode sibling;
}
/**
* 实现函复制一个复杂链表。在复杂链表中。每一个结点除了有一个next字段指向下一个结点外,
* 另一个sibling字段指向链表中的随意结点或者NULL
*
* @param head 链表表头结点
* @return 复制结点的头结点
*/
public static ComplexListNode clone(ComplexListNode head) {
// 假设链表为空就直接返回空
if (head == null) {
return null;
}
// 先复制结点
cloneNodes(head);
// 再链接sibling字段
connectNodes(head);
// 将整个链表拆分,返回复制链表的头结点
return reconnectNodes(head);
}
/**
* 复制一个链表,而且将复制后的结点插入到被复制的结点后面,仅仅链接复制结点的next字段
*
* @param head 待复制链表的头结点
*/
public static void cloneNodes(ComplexListNode head) {
// 假设链表不空,进行复制操作
while (head != null) {
// 创建一个新的结点
ComplexListNode tmp = new ComplexListNode();
// 将被复制结点的值传给复制结点
// tmp.value = head.value;
///////////////////////////////////////////////////////////////////////////////////////////
// TODO 此处为了做測试。让复制结点的值都添加了100,假设不须要能够将以下一个行凝视掉,打开上一行。
tmp.value = head.value + 100;
///////////////////////////////////////////////////////////////////////////////////////////
// 复制结点的next指向下一个要被复制的结点
tmp.next = head.next;
// 被复制结点的next指向复制结点
head.next = tmp;
// 到些处就已经完毕了一个结点的复制而且插入到被复制结点的后面
// heed指向下一个被复制结点的位置
head = tmp.next;
}
}
/**
* 设置复制结点的sibling字段
*
* @param head 链表的头结
*/
public static void connectNodes(ComplexListNode head) {
// 如链表不为空
while (head != null) {
// 当前处理的结点sibling字段不为空,则要设置其复制结点的sibling字段
if (head.sibling != null) {
// 复制结点的sibling指向被复制结点的sibling字段的下一个结点
// head.next:表求复制结点。
// head.sibling:表示被复制结点的sibling所指向的结点,
// 它的下一个结点就是它的复制结点
head.next.sibling = head.sibling.next;
}
// 指向下一个要处理的复制结点
head = head.next.next;
}
}
/**
* 刚复制结点和被复制结点拆开,还原被复制的链表,同一时候生成监制链表
*
* @param head 链表的头结点
* @return 复制链表的头结点
*/
public static ComplexListNode reconnectNodes(ComplexListNode head) {
// 当链表为空就直接返回空
if (head == null) {
return null;
}
// 用于记录复制链表的头结点
ComplexListNode newHead = head.next;
// 用于记录当前处理的复制结点
ComplexListNode pointer = newHead;
// 被复制结点的next指向下一个被复制结点
head.next = newHead.next;
// 指向新的被复制结点
head = head.next;
while (head != null) {
// pointer指向复制结点
pointer.next = head.next;
pointer = pointer.next;
// head的下一个指向复制结点的下一个结点。即原来链表的结点
head.next = pointer.next;
// head指向下一个原来链表上的结点
head = pointer.next;
}
// 返回复制链表的头结点
return newHead;
}
/**
* 输出链表信息
*
* @param head 链表头结点
*/
public static void printList(ComplexListNode head) {
while (head != null) {
System.out.print(head.value + "->");
head = head.next;
}
System.out.println("null");
}
/**
* 推断两个链表是否是同一个链表,不是值相同
*
* @param h1 链表头1
* @param h2 链表头2
* @return true:两个链表是同一个链表。false:不是
*/
public static boolean isSame(ComplexListNode h1, ComplexListNode h2) {
while (h1 != null && h2 != null) {
if (h1 == h2) {
h1 = h1.next;
h2 = h2.next;
} else {
return false;
}
}
return h1 == null && h2 == null;
}
public static void main(String[] args) {
// -----------------
// \|/ |
// 1-------2-------3-------4-------5
// | | /|\ /|\
// --------+-------- |
// -------------------------
ComplexListNode head = new ComplexListNode();
head.value = 1;
head.next = new ComplexListNode();
head.next.value = 2;
head.next.next = new ComplexListNode();
head.next.next.value = 3;
head.next.next.next = new ComplexListNode();
head.next.next.next.value = 4;
head.next.next.next.next = new ComplexListNode();
head.next.next.next.next.value = 5;
head.sibling = head.next.next;
head.next.sibling = head.next.next.next.next.next;
head.next.next.next.sibling = head.next;
ComplexListNode tmp = head;
printList(head);
ComplexListNode newHead = clone(head);
printList(head);
System.out.println(isSame(head, tmp));
printList(newHead);
System.out.println(isSame(head, newHead));
// 有指向自身的情况
// -----------------
// \|/ |
// 1-------2-------3-------4-------5
// | | /|\ /|\
// | | -- |
// |------------------------|
ComplexListNode head2 = new ComplexListNode();
head2.value = 1;
head2.next = new ComplexListNode();
head2.next.value = 2;
head2.next.next = new ComplexListNode();
head2.next.next.value = 3;
head2.next.next.next = new ComplexListNode();
head2.next.next.next.value = 4;
head2.next.next.next.next = new ComplexListNode();
head2.next.next.next.next.value = 5;
head2.next.sibling = head2.next.next.next.next;
head2.next.next.next.sibling = head2.next.sibling;
head2.next.next.sibling = head2.next.next;
System.out.println("\n");
tmp = head2;
printList(head2);
ComplexListNode newHead2 = clone(head2);
printList(head2);
System.out.println(isSame(head2, tmp));
printList(newHead2);
System.out.println(isSame(head2, newHead2));
ComplexListNode head3 = new ComplexListNode();
head3.value = 1;
System.out.println("\n");
tmp = head3;
printList(head3);
ComplexListNode newHead3 = clone(head3);
printList(head3);
System.out.println(isSame(head3, tmp));
printList(newHead3);
System.out.println(isSame(head3, newHead3));
System.out.println("\n");
ComplexListNode head4 = clone(null);
printList(head4);
}
}
执行结果:
注意:划红线部分是为了区分原链表和复制链表,详细还原见代码凝视。
【剑指Offer学习】【面试题26:复杂链表的复制】的更多相关文章
- 《剑指offer》面试题26 复杂链表的复制 Java版
(定义一个新的数据结构,每个节点除了具有普通链表的next域外,还有一个额外的引用指向任意节点.我们要对由该特殊数据结构形成的链表进行复制.) 我的方法:也就是克隆一个这种特殊链表,很快想到先不考虑原 ...
- 《剑指offer》面试题35. 复杂链表的复制
问题描述 请实现 copyRandomList 函数,复制一个复杂链表.在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null. ...
- 【剑指offer】面试题 24. 反转链表
面试题 24. 反转链表
- 【剑指offer】面试题 18. 删除链表的节点
面试题 18. 删除链表的节点
- (剑指Offer)面试题26:复杂链表的复制
题目: 请实现函数ComplexListNode* Clone(ComplexListNode* pHead),复制一个复杂链表. 在复杂链表中,每个结点除了有一个pNext指针指向下一个结点之外,还 ...
- 【剑指offer】面试题26:复杂链表的复制
题目: 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点). 思路: 复制自身到下一个结点: 设置新结点的random指针: 分离链表. 注意:判 ...
- 【剑指offer】面试题26:复制的复杂链条
def copyRandomList(self, head): if None == head: return None phead = head while phead: pnext = phead ...
- 【剑指Offer】面试题26. 树的子结构
题目 输入两棵二叉树A和B,判断B是不是A的子结构.(约定空树不是任意一个树的子结构) B是A的子结构, 即 A中有出现和B相同的结构和节点值. 例如: 给定的树 A: 3 / \ ...
- 《剑指offer》面试题26. 树的子结构
问题描述 输入两棵二叉树A和B,判断B是不是A的子结构.(约定空树不是任意一个树的子结构) B是A的子结构, 即 A中有出现和B相同的结构和节点值. 例如: 给定的树 A: 3 / ...
- (剑指Offer)面试题15:链表中倒数第k个结点
题目: 输入一个链表,输出该链表中倒数第k个结点. 例如:链表中有6个结点,从头到尾依次为1,2,3,4,5,6,则该链表的倒数第3个结点为4. 链表结点定义: struct ListNode{ in ...
随机推荐
- [源码管理] ubuntu中svn简明用法:服务器搭建+客户端使用
本文是对网络上前人的优秀文章加以实践验证后所整理(修正或补充) 第一部分:svn服务器搭建(主要是四步走) 参考:http://www.son1c.cn/show/920.html 一,安装Subve ...
- python 下 excel,csv 文件的读写
python 可以用利用xlrd 库读取数据excel数据,可以用xlwt写入excel数据,用csv 操作csv文件 xlrd xlwt python 模块 官方链接 https://pypi. ...
- Python3.6 import源文件与编译文件的关系
小结: 在Python3.6中 源文件存在时,import会比较源文件与__pycache__里相应文件的时间戳,来决定是否重新生成缓存编译文件 源文件不存在时,import会导入相应的.pyc文件 ...
- cropper+pillow处理上传图片剪裁(二)
上次说到处理上传头像的方法是临时保存在本地,其实这样做并不妥,而且修改后的头像重新上传到model中也很麻烦,差了很多资料,解决了这个问题 大致思路:用户上传原图和修改数据—PIL修改后将图片保存为内 ...
- webpack打包大概流程
webpack 步骤 1. 新建一个webpack.config.prod.js 2. 压缩bundle.js和index.html //设置为生产环境 new webpack.DefinePlugi ...
- 基于MapReduce的贝叶斯网络算法研究参考文献
原文链接(系列):http://blog.csdn.net/XuanZuoNuo/article/details/10472219 论文: 加速贝叶斯网络:Accelerating Bayesian ...
- 杭电1003 Max Sum TLE
这一题目是要求连续子序列的最大和,所以在看到题目的一瞬间就想到的是把所有情况列举出来,再两个两个的比较,取最大的(即为更新最大值的意思),这样的思路很简单,但是会超时,时间复杂度为O(n^3),因为有 ...
- (转)RabbitMQ学习之路由(java)
http://blog.csdn.net/zhu_tianwei/article/details/40887755 参考:http://blog.csdn.NET/lmj623565791/artic ...
- H3C三层交换机S5500初始配置+网络访问策略
DHCP中继配置命令 dhcp relay address-check enable 命令用来使能DHCP 中继的地址匹配检查功能. undo dhcp relay address-check ena ...
- Aeroplane chess HDU - 4405_数学期望_逆推
Code: #include<cstdio> #include<algorithm> #include<cstring> using namespace std; ...