题目:

请实现函数ComplexListNode* Clone(ComplexListNode* pHead)。复制一个复杂链表。

在复杂链表中。每个节点除了一个m_pNext指针指向下一个节点外,另一个m_pSibling指向链表中的随意节点或者NULL,节点的定义例如以下:

package com.aii.algorithm;

public class Node {
int value;
Node next;
Node sibling; public Node(int value) {
this.value = value;
} public Node() {
} }

一.思路:

能够分两步来实现:

1.先复制链表。sibling就用旧链表的,照搬。

2.再复制silbing

怎么复制sibling,这个借助一个HashMap(在O(1)时间内可以找到),将Node与其复制的Node'的映射关系存到HashMap中。

在第二步改动sibling的时候,依据原先sibling的Node去Map中找,找到相应的那个就是他应该指向的那个。

代码实现:

package com.aii.algorithm;

import java.util.HashMap;
import java.util.Map; public class CloneNodes {
// 第一步:复制链表
// 第二步:复制sibing的指针位置
public Node clone(Node head) {
Map<Node, Node> map = new HashMap<Node, Node>(); // copy linkedlist
Node newHead = cloneNode(head, map); // copy silbing points
Node tmpNewHead = newHead;
while (tmpNewHead != null) {
// get from mapping
tmpNewHead.sibling = map.get(tmpNewHead.sibling);
tmpNewHead = tmpNewHead.next;
}
return newHead;
} // 1.递归克隆
// 2.同一时候将Node,以及Node'的映射关系放入到map中,方便map.next查找
private Node cloneNode(Node head, Map<Node, Node> map) {
if (head == null) {
return null;
}
Node node = new Node();
node.next = cloneNode(head.next, map);
node.sibling = head.sibling;
map.put(head, node);
node.value = head.value;
return node;
}
}

二、

这里借助了HashMap

假设不借助HashMap,又要在O(n)时间完毕?

不使用Map,在改动sibling的时候。麻烦之处在哪?

在于找不到新复制的节点。

下图:

比方说要在A'位置找A'的silbing,那就要A'与A一起往前走,直到某个节点Node==A.sibling这个时候相应的Node'也应该是A'.silbing。

可是这种时间复杂度为O(n*n)

这里有一个好的办法:

分三步走:

1.将新复制的链表穿插到旧的链表中

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

2.这样子就行依据左右位置的旧的节点找到sibling位置了

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

3.还原。

代码实现:

package com.aii.algorithm;

public class CloneNodes2 {

	// 1.将新的节点插入到链表原始节点的后面
// 2.将新的节点的sibling的指针给赋值。是原先值的next
// 3.再将新的节点链表从中独立出来
public Node clone(Node head) {
Node tmp = head;
// 1.第一步。插入新的节点
while (tmp != null) {
Node next = tmp.next;
Node node = new Node();
node.value = tmp.value;
node.next = tmp.next;
tmp.next = node;
//
tmp = next;
} // 2.第二步,设置sibling
int count = 0;
tmp = head;
Node nodeNext = null;
while (tmp != null) {
if (count++ % 2 == 0) {
nodeNext = tmp.next;
} else {
tmp.next = nodeNext.next;
}
tmp = tmp.next;
} // 3.第三步。将新的链表独立出来,而且还原原先的链表
tmp = head;
Node newHead = null;
count = 0;
while (tmp != null) {
tmp.next = tmp.next.next;
newHead = tmp.next; tmp = tmp.next;
} return newHead;
}
}

三、測试用例:

因为引用关系比較复杂,toStringeasy引发空指针。这里附上測试用例:

package com.aii.algorithm;

import org.junit.Before;
import org.junit.Test; public class CloneNodes2Test {
private Node head = new Node('a'); @Before
public void init() {
Node n2 = new Node('b');
Node n3 = new Node('c');
Node n4 = new Node('d');
Node n5 = new Node('e'); head.next = n2;
n2.next = n3;
n3.next = n4;
n4.next = n5; //
head.sibling = n3;
n2.sibling = n5;
n3.sibling = n2;
} @Test
public void test() {
printNode(head);
Node node = new CloneNodes().clone(head);
System.out.println("-----");
printNode(node);
System.out.println("-----");
printNode(head);
} private void printNode(Node node) {
Node tmp = node;
while (tmp != null) {
int sibling = -1;
if (tmp.sibling != null) {
sibling = tmp.sibling.value;
}
int next = -1;
if (tmp.next != null) {
next = tmp.next.value;
}
System.out.print("value:" + (char) tmp.value);
System.out.print("\tsibling:" + (char) sibling);
System.out.println("\tnext:" + (char) next);
tmp = tmp.next;
}
}
}

结果:

value:a sibling:cnext:b

value:b sibling:enext:c

value:c sibling:bnext:d

value:d sibling:?next:e

value:e sibling:?next:?

-----

value:a sibling:cnext:b

value:b sibling:enext:c

value:c sibling:bnext:d

value:d sibling:?next:e

value:e sibling:?next:?

-----

value:a sibling:cnext:b

value:b sibling:enext:c

value:c sibling:bnext:d

value:d sibling:?next:e

value:e sibling:?

next:?

剑指offer面试题26-复杂链表的复制的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. 剑指offer面试题15:链表中倒数第K个节点

    题目:输入一个链表,输出该链表的倒数第K个节点.为了符合大多数人的习惯,本题从1开始计数,即链表尾节点是倒数第一个节点. 解题思路: 解法一:一般情况下,单向链表无法从后一个节点获取到它前面的节点,可 ...

  9. 剑指offer——面试题23:链表中环的入口节点

    函数: ListNode* MeetingNode(ListNode* pHead) { if(pHead==nullptr) return nullptr; ListNode* quickNode= ...

随机推荐

  1. jQuery Video Extend

    HTML5视频扩展插件 能够加入Logo 加入标记 用法: 下载:jquery-video-extend <script src="js/jquery-2.1.4.min.js&quo ...

  2. UVA 10593 Kites DP

    The season of flying kites is well ahead. So what? Let us make an inventory for kites. We are givena ...

  3. php中的self关键字和this关键字的区别和联系

    php中的self关键字和this关键字的区别和联系 面向对象编程(OOP,Object OrientedProgramming)现已经成为编程人员的一项基本技能.利用OOP的思想进行PHP的高级编程 ...

  4. [jzoj 5664] [GDOI2018Day1模拟4.6] 凫趋雀跃 解题报告(容斥原理)

    interlinkage: https://jzoj.net/senior/#contest/show/2703/3 description: solution: 考虑容斥原理,枚举不合法的走的步数 ...

  5. 个人作业—Alpha项目测试

    这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass2 这个作业要求在哪里 https://edu.cnblo ...

  6. 关于ubuntu中文输入调用不出来的解决办法,具体如正文。

    卸载了 fcitx sudo apt-get remove fcitx 重启 sudo reboot 重新安装 fcitxsudo apt-get install fcitx 安装拼音输入法sudo ...

  7. Js radio

    <input type="radio" name="sex" value="1" />男 <input type=&quo ...

  8. StatusBarUtils工具类

    import android.app.Activity; import android.app.Dialog; import android.content.Context; import andro ...

  9. CF1012B Chemical table 构造_思维_并查集

    我们可以将横坐标和纵坐标看成是点.发现这些点之间是有传递性的. 题中说明,如果有矩阵中三个顶点被选,则底角的点也会被覆盖,发现这些点之间是有传递性的.那么我们最终达到的目的就是使整个图中只有 111 ...

  10. 百度图标echarts.js的使用

    echarts官网:http://echarts.baidu.com/api.html#echarts echarts是百度公司开的一种开源制作图片工具,是一个专门制作图表的开源工具,功能非常强大,地 ...