宇宙经典面试题:随机链表复制

52 阅读1分钟

题意描述

给定一个链表,这个链表的每个结点除了value、next,还包括额外的一个rand指针指向这个链表中的其它结点。称这种链表为随机链表。

现在要求在不使用额外空间的情况下复制这个随机链表。

题目分析

这道题有点难度,在面试那种面对面的紧张状态下如果能够一次性写对还是非常有挑战性的。

这道题难就难在不使用额外的空间,这就要求我们在狭窄的、有限的几个指针之间辗转腾挪。

第一步:为链表中的每个结点创建影子结点,使用结点的rand指向影子结点,影子结点的next指向原结点的rand。
第二步:完善影子结点的rand指针。把影子结点的rand指针搞对,影子结点的rand指针应该指向影子链表中的结点,影子链表和原链表的结点可以通过原结点的rand指针实现一一对应。影子结点的rand=影子结点的next.rand
第三步:完善影子结点的next指针和原结点的rand指针。

源代码

from os import link
import random


class Node:
    def __init__(self, v, link_id):
        self.next = None
        self.rand = None
        self.value = v
        self.link_id = link_id


def tos(n: Node):
    a = []
    while n:
        a.append(
            (
                n.value,
                n.next.value if n.next else -1,
                n.rand.value if n.rand else -1,
                n.link_id,
            )
        )
        n = n.next
    return str(a)


def copy_rand_list(n: Node):
    head = Node(0, 1)
    i = n
    while i:
        now = Node(i.value, 1)
        now.next = i.rand
        i.rand = now
        i = i.next
    head.next = n.rand
    i = n
    while i:
        j = i.rand
        j.rand = j.next.rand if j.next else None
        i = i.next
    i = n
    while i:
        j = i.rand
        i.rand = j.next
        j.next = i.next.rand if i.next else None
        i = i.next
    return head.next


def make_list():
    a = [Node(i, 0) for i in range(20)]
    for i in range(len(a) - 1):
        a[i].next = a[i + 1]
        a[i].rand = a[random.randint(0, len(a) - 1)]
    return a[0]


def main():
    n = make_list()
    ns = tos(n)
    print(ns)
    nn = copy_rand_list(n)
    nns = tos(nn)
    print(nns)
    print(tos(n))


main()