题目要求:
请将一个特殊链表复制一份,一个特殊的链表节点结构如下:
node类中包含:
value:表示节点的值
next:表示下一个节点
rand:表示随机指向的任意一个节点
题目分析:
相当于,就是在一个普通单链表的基础上,每个节点多了一个可以任意指向的指针,比如:1–>2–>3,然后1的rand指向3,2的rand指向1,3的rand指向null。
要想复制链表,首先,需要将原链表遍历一遍,然后,复制出每个节点,如果只是普通的复制单链表问题,那么,将他们依次连接起来就行了。但是,这题的特殊之处就在于,除了next,每个节点还有个rand指针,那么,如果我想找到1的rand是3,那么,在复制的节点1中,rand应该指向复制的3,但是,我怎么能拿到复制的3?假设在原来的链表中,3在1的前面呢?那么,就算在原来的链表中,我也不可能通过next找到3,只能通过原来链表的rand找到原来的3。因此,rand指向的节点,只能通过rand来找到,因为如果rand指向的节点在前面,next就找不到。那么,问题来了,我们可以在原来的链表中,通过rand指针找到rand指向的节点,可是,怎么确定新创建的节点,哪个是原来rand指向的节点复制的呢?因此,此题的关键点在于,怎么把新创建的节点和原来的节点对应起来。
笔试思路:
既然明白了此题的关键点在于,怎么把新创建的节点和原来一节点一一对应起来,那么问题就很清楚了。一一对应关系,想到了什么数据结构?没错,就是散列表map。用map把原来的节点与复制的节点一一对应起来。然后,第一遍遍历的时候,依次复制节点,并且把复制后的1和原来的1节点,放进map中,然后,第二遍遍历,找到1的next和rand,把1的next和rand指向的内容,在map中查找到对应的复制后的节点,然后把1复制后的节点,链接上他们,然后依次进行。
这是笔试中最容易的做法,只需要借助map来保存对应关系。缺点是空间复杂度是O(n),因此保存map需要开辟空间。
面试思路:
如果要求你用空间复杂度O(1)来实现,怎么写?
其实就是在问你,如果不借助额外空间map来实现一一对应关系,怎么实现新创建的节点和原来的节点一一对应?
其实,可以这样考虑,既然不能申请额外空间来对应,那么,因此链表容易链接断开的特殊性,是否可以直接把复制的节点,直接链接在原来节点的后面呢?
比如:
1–>1的复制节点–>2–>2的复制节点…
这样,我们可以每次取两个节点,比如,分别是1和1的复制节点,然后,复制1的rand节点就是原来1节点的rand的next,这样就可以把复制后的rand节点链接起来了。然后,再遍历一遍,把相应的复制的1的next节点就是复制的1的节点的next的next,就也把next指针链接好了。这样,就完成了复制。