题目:

请实现一个cloneNode方法,复制一个复杂链表。

在复杂链表中,每个结点除了有一个next指针指向下一个结点之外,还有一个random指向链表中的任意结点或者NULL。

结点的定义如下:

public static class ListNode {
int val;
ListNode next;
ListNode random; ListNode(int x) {
val = x;
}
}

思路:

方法1:

复制原始链表上的每一个结点,并通过next连接起来;然后再设置每个结点的random指针。

假设原始链表中某个结点N的random指针指向结点S,那么就需要从头到尾遍历查找结点S,如果从原始链表的头指针开始,经过m步之后达到结点S,那么在复制链表中的结点N'的random指针指向的结点也是距离复制链表s步的结点。通过这种办法就可以为复制链表上的每个结点设置random指针。

时间复杂度:O(N^2)

方法2:

方法1是通过链表查找来得到random指针所指向的结点,实际上我们可以通过空间换取时间,将原始链表和复制链表的结点通过哈希表对应起来,这样查找的时间就从O(N)变为O(1)。具体如下:

复制原始链表上的每个结点N创建N',然后把这些创建出来的结点用pNext连接起来。同时把<N,N'>的配对信息方法一个哈希表中;然后设置复制链表中的每个结点的random指针,如果原始链表中结点N的random指向结点S,那么在复制链表中,对应的N'应该指向S'。

时间复杂度:O(N)

根据方法2,我们可以写出代码:

private static ListNode cloneNode(ListNode head2) {
if (head2 == null) {
return null;
}
Map<ListNode, ListNode> map1 = new HashMap<>();
ListNode newHead = new ListNode(head2.val);
map1.put(head2, newHead);
ListNode head = newHead;
// 复制节点和next指针
for (ListNode cur = head2.next; cur != null; cur = cur.next) {
head.next = new ListNode(cur.val);
head = head.next;
map1.put(cur, head);
}
head = newHead;
// 复制random节点
ListNode ranNode = null;
for (ListNode cur = head2; cur != null; cur = cur.next) {
ranNode = map1.get(cur.random);
head.random = ranNode;
head = head.next;
}
return newHead;
}

方法3:

在不使用辅助空间的情况下实现O(N)的时间效率。

第一步:根据原始链表的每个结点N创建对应的N',然后将N‘通过next接到N的后面;

第二步:设置复制出来的结点的random。假设原始链表上的N的random指向结点S,那么其对应复制出来的N'是N->pNext指向的结点,同样S'也是结点S->next指向的结点。

第三步:把长链表拆分成两个链表,把奇数位置的结点用next连接起来的就是原始链表,把偶数位置的结点通过next连接起来的就是复制链表。

如图:

根据方法3,我们可以写出代码:

// 不要额外空间的时间复杂度为O(N)
private static ListNode cloneNode2(ListNode head2) {
if (head2 == null) {
return null;
}
// 复制节点和next指针
ListNode cur = head2;
while (cur != null) {
ListNode prev = cur.next;
ListNode clone = new ListNode(cur.val);
cur.next = clone;
cur.next.next = prev;
cur = prev;
}
ListNode old = head2;
ListNode clone = old.next;
while (clone != null) {
if (old.random != null) {
clone.random = old.random.next;
}
old = clone.next;
if (old != null) {
clone = old.next;
} else {
break;
}
}
ListNode res = oddEvenList(head2);
return res;
}

上面的代码可以得到图4.10的结构,而这个时候我们希望把链表分开,老的节点和复制的节点各分为一边,于是乎,出现了奇偶节点的变换(LeetCode328题):

public static ListNode oddEvenList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode oddNode = head;
ListNode evenNode = head.next;
ListNode cur = evenNode.next;
ListNode evenTemp = evenNode;
int index = 3;
while (cur != null) {
if (index % 2 == 0) {
evenNode.next = cur;
evenNode = evenNode.next;
} else {
oddNode.next = cur;
oddNode = oddNode.next;
}
cur = cur.next;
index++;
}
evenNode.next = null;
return evenTemp;
}

返回的evenTemp节点就是我们复制链表的第一个节点!

剑指offer35----复制复杂链表的更多相关文章

  1. 剑指Offer35 两个链表第一个公共结点

    /************************************************************************* > File Name: 35_FirstC ...

  2. 剑指Offer-35.两个链表的第一个公共结点(C++/Java)

    题目: 输入两个链表,找出它们的第一个公共结点. 分析: 先统计两个链表的长度,计算他们的差值,然后将两个链表对齐,再去寻找公共节点即可. 程序: C++ class Solution { publi ...

  3. 剑指 Offer 35. 复杂链表的复制

    剑指 Offer 35. 复杂链表的复制 Offer_35 题目详情 方法一 可以使用一个HashMap来存储旧结点和新结点的映射. 这种方法需要遍历链表两遍,因为需要首先知道映射关系才能求出next ...

  4. 【剑指Offer】复杂链表的复制 解题报告(Python)

    [剑指Offer]复杂链表的复制 解题报告(Python) 标签(空格分隔): 剑指Offer 题目地址:https://www.nowcoder.com/ta/coding-interviews 题 ...

  5. 《剑指offer》复杂链表的复制

    本题来自<剑指offer> 反转链表 题目: 思路: C++ Code: Python Code: 总结:

  6. 《剑指offer》 反转链表

    本题来自<剑指offer> 反转链表 题目: 输入一个链表,反转链表后,输出新链表的表头. 思路: 需要三个变量,来保存当前节点的,前面节点和反转后的节点. C++ Code: /* st ...

  7. 剑指offer35题:第一个只出现一次的字符+剑指offer55题:字符流中第一个不重复的字符+剑指offer51题:数组中重复的数字

    在看剑指offer的时候,感觉这三个题目很像,都是用哈希表可以解决,所以把这三个题整理出来,以供复习. 剑指offer35题:第一个只出现一次的字符 题目描述:在字符串中找出第一个只出现一次的字符.如 ...

  8. 剑指Offer:删除链表的节点【18】

    剑指Offer:删除链表的节点[18] 题目描述 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3-& ...

  9. 剑指Offer:反转链表【24】

    剑指Offer:反转链表[24] 题目描述 输入一个链表,反转链表后,输出新链表的表头. 解题分析 这道题我才发现我是属于那种真的笨,图都画出来了流程写不出来.看了别人的代码,总觉得自己差一步. 这也 ...

  10. [剑指 Offer 18. 删除链表的节点]

    [剑指 Offer 18. 删除链表的节点] 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点. 返回删除后的链表的头节点. 注意:此题对比原题有改动 示例 1: 输入: head ...

随机推荐

  1. CORE EF生成ORACLE数据库模型报错问题记录

    需求:最近在新开发一套在LINUX运行的API接口,需要用到net core api框架以及oracle数据库,首先需要解决的就是连接数据库问题,由于是DBFirst 加上之前很多老表不规范,导致了c ...

  2. _stscanf_s (sscanf)正则表达式

    _stscanf_s (sscanf)正则表达式     {%[*] [width] [{h | l | I64 | L}]type  |  ' ' |  '\t' | '\n' | 非%符号}, 注 ...

  3. Jboss未授权访问部署木马 利用exp

    查看系统名称 java -jar jboss_exploit_fat.jar -i http://www.any.com:8080/invoker/JMXInvokerServlet get jbos ...

  4. 使用ABAP批量下载Markdown源文件里的图片到本地

    执行我github里的这个report: 选中一段markdown文档,ctrl C: 然后直接执行report: 执行完毕: 所有文件都下载到本地文件夹: 这个report使用到的工具类:zcl_c ...

  5. 【坑】Mybatis原始获取配置方式,获取配置失败

    错误环境: mysql版本:6.0.6 mybatis 3.4.1 idea 2017.1.2 maven 3.5.0 错误描述: 配置经路径见图1,classpath是java文件夹 获取配置的代码 ...

  6. oracle内核参数详解

    一.前言 在生产中,我们安装oracle数据库时,为达到最优我们需要对操作系统的内核参数进行一定的调整.主要从内存.cpu.io以及网络等方面,根据实际情况进行调整.以下参数可供大家参考,如有不当之处 ...

  7. LoadRunner(7)

    一.参数化策略 1.Select next row(How? 如何取?)取值方式 选择下一行 1)Sequential:顺序的 每个VU都从第一行开始,顺序依次向下取值: 数据取完可以从头循环重复使用 ...

  8. 十一届河南省赛-checkpoints(个人解法)-能AC代码

    大致题意: zznuoj,大致题意:从A点出发达到B点去解救人质,再从B点返回到A点,经历第二遍的点只计算一次即可,AB两点不计数!求完成任务最少需要经过的点数. 大致思路:暴力!从起点到终点,和从终 ...

  9. import this: python原则

    >>> import this The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is ...

  10. Elasticsearch:运用search_after来进行深度分页

    在上一篇文章 "Elasticsearch:运用scroll接口对大量数据实现更好的分页",我们讲述了如何运用scroll接口来对大量数据来进行有效地分页.在那篇文章中,我们讲述了 ...