如图1所示,有一条单链表,其节点除了有next指针外,还有一个random指针。random指针可指向单链表中的任意节点,包括它自身。random指针一旦指定,便不再更改。请设计算法,复制此单链表,并给出时间复杂度。

  图1 带有random指针的单链表

解法1. 时间复杂度为O(n*n)

先按next指针,将链表复制一份。使用p1指向原链表的头节点,p2指向p1指向的节点的random节点,p3指向p1的next节点,cnt记录p3移动的步数,p4指向新链表的头节点。对比p3和p2的指向:如果p2和p3地址不一致,则p3移向本节点的next节点,并记录移动的频数加1。如此反复,直到p3指向的地址与p2指向的地址一致。使用p5指向p4的next节点,再向后移动cnt次,得到p4指向的节点的random指针应该指向的位置。将p1和p4同时移向各自的next。如此反复。

解法2. 时间复杂度为O(2n)

想要降低时间复杂度,就需要增加空间复杂度,拿空间换时间。解法1的时间复杂度高的原因为查找新链表中random指针的指向,哈希表可解决查找慢的问题。

可建立一个hash表,使用原链表的节点的地址的hash值作下标,使用新链表对应的地址作value。这样遍历原链表一遍后,节点的random指向为NULL的新链表可建立起来,并且建立了一张hash表。再遍历一遍,p1指向原链表中某节点,p2指向新链表中对应的某节点。将p1的random指针指向的地址做hash后,可得到hash表中新链表对应的地址值。再将p2的random指针指向该地址即可。如此反复。

解法3. 时间复杂度为O(2n),空间复杂度为O(1)

解法2所花费的空间有些大了,解决法通破坏原链表的方法,代替了hash表,解决了查找random指针指向的问题。虽然原链表被破坏了,但可被恢复到原样。

首先遍历原链表,同时建立新链表。将新链表的random指针指向原链表对应节点的next节点,将原链表的next指针指向新链表的对应节点。

再遍历一次原链表和新链表,p1指向原链表的某节点,p2指向新链表的对应节点。从p1可知random指向的节点,从此节点的next指针可知新链表的对应节点,使用p3指针指向该节点。将p1的next指向p2的random指针指向的节点,再将p2的random指针指向p3。p1和p2均指向自己的next节点。如此反复。

解法3的示意图如下:

复制带有random指针的单链表的更多相关文章

  1. 40深入理解C指针之---指针与单链表

    一.指针与单链表 1.定义:通过使用指针将节点(结点)链接起来成为链表 2.节点(结点): 1).数据域:主要用来存储数据,可以基本数据类型,也可以是构造数据类型: 2).指针域:主要用来当前节点(结 ...

  2. [leetcode]138. Copy List with Random Pointer复制带有随机指针的链表

    public RandomListNode copyRandomList(RandomListNode head) { /* 深复制,就是不能只是复制原链表变量,而是做一个和原来链表一模一样的新链表, ...

  3. LeetCode——Copy List with Random Pointer(带random引用的单链表深拷贝)

    问题: A linked list is given such that each node contains an additional random pointer which could poi ...

  4. 复制一个带random指针的链表

    一个单链表,其中除了next指针外,还有一个random指针,指向链表中的任意某个元素.如何复制这样一个链表呢? 通过next来复制一条链是很容易的,问题的难点在于如何恰当地设置新链表中的random ...

  5. 【链表问题】打卡9:将单链表的每K个节点之间逆序

    前言 以专题的形式更新刷题贴,欢迎跟我一起学习刷题,相信我,你的坚持,绝对会有意想不到的收获.每道题会提供简单的解答,如果你有更优雅的做法,欢迎提供指点,谢谢. 注:如果代码排版出现了问题麻烦通知我下 ...

  6. 数据结构 - 动态单链表的实行(C语言)

    动态单链表的实现 1 单链表存储结构代码描述 若链表没有头结点,则头指针是指向第一个结点的指针. 若链表有头结点,则头指针是指向头结点的指针. 空链表的示意图: 带有头结点的单链表: 不带头结点的单链 ...

  7. 《数据结构》2.3单链表(single linked list)

    //单链表节点的定义 typedef struct node { datatype data; struct node *next; }LNode,*LinkList; //LNode是节点类型,Li ...

  8. 数组、单链表和双链表介绍 以及 双向链表的C/C++/Java实现

    概要 线性表是一种线性结构,它是具有相同类型的n(n≥0)个数据元素组成的有限序列.本章先介绍线性表的几个基本组成部分:数组.单向链表.双向链表:随后给出双向链表的C.C++和Java三种语言的实现. ...

  9. 删除单链表倒数第n个节点

    基本问题 如何删除单链表中的倒数第n个节点? 常规解法 先遍历一遍单链表,计算出单链表的长度,然后,从单链表头部删除指定的节点. 代码实现 /** * * Description: 删除单链表倒数第n ...

随机推荐

  1. Android之AndroidManifest.xml文件解析

    转自:Android学习笔记之AndroidManifest.xml文件解析 一.关于AndroidManifest.xml AndroidManifest.xml 是每个android程序中必须的文 ...

  2. awesome awesomeness

    Awesome Awesomeness A curated list of amazingly awesome awesomeness.Also available on: Awesome-Aweso ...

  3. Java线程池的工作原理与实现

    简单介绍 创建线程有两种方式:继承Thread或实现Runnable.Thread实现了Runnable接口,提供了一个空的run()方法,所以不论是继承Thread还是实现Runnable,都要有自 ...

  4. iScroll-5拉动刷新功能实现与iScroll-4上拉刷新的一点改进

    近来在学习移动设备的应用开发,接触了jQuery mobile,在网上查阅相关资料时发现一个叫”iScroll“的小插件.其实这个iScroll插件跟jQuery mobile没有多大关系,并不是基于 ...

  5. 在线API,桌面版,jquery,css,Android中文开发文档,JScript,SQL掌用实例

    学习帮助文档大全 jquery,css,Android中文开发文档,JScript,SQL掌用实例 http://api.jq-school.com/

  6. C# List 使用方法 支持FrameWork2.0 环境

    List查找指定数据 var tmpBillInputCheckList = BillInputCheckList.FindAll(m => m.BillDetailGuid == tmpBil ...

  7. sh脚本执行Java程序

    1.不引用Jar包或者资源文件夹 最简单的程序Hello World. 首先创建Hello.java public class Hello { public static void main(Stri ...

  8. POJ 2455 Secret Milking Machine (二分+无向图最大流)

    [题意]n个点的一个无向图,在保证存在T条从1到n的不重复路径(任意一条边都不能重复)的前提下,要使得这t条路上经过的最长路径最短. 之所以把"经过的最长路径最短"划个重点是因为前 ...

  9. mysql qps tps

    (1)QPS(每秒Query量) QPS = Questions(or Queries) / seconds mysql > show global status like 'Question% ...

  10. 一滴一点vim(学习+备忘)

    普通模式: h j k l 分别是左下上右方式移动: :w 保存修改 :q 推出 :wq 保存修改并退出 :q! 放弃修改强制推出 x 删除光标所在位置字符 i 在光标所以位置插入字符 删除类命令: ...