剑指 Offer 35. 复杂链表的复制 #Java 暴力解、回溯法

89 阅读2分钟

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

解题思路

题目分析:这道题的关键在于每个节点都包含一个random指针,指向随机的节点,而需要给random复制的时候,random所指向的复制节点很有可能还没有创建,如何处理random指针问题是这道题的关键所在。

解法一:暴力解法

思路

这里我第一个想到的就是先复制链表,然后再遍历链表对节点中的random指针赋值。这里需要注意的是怎么确定random指针要指向的节点是哪一个

  • 用地址肯定不行,因为复制过来的节点地址不一样
  • 用val值也不行,如果有多个相同的val值就会导致指向的节点和原链表不一致
  • 用索引是可以的,链表是有序的,所以索引可以用来确定复制链表中的节点对应原链表中的哪个节点

所以,整个函数设计如下:

  1. 先复制链表,不处理random指针
  2. 同时遍历两个两个链表
  3. 确定原链表中节点random指向节点的索引值
  4. 让复制链表中的节点的random指向相同索引位置的节点
  5. 复制完成

代码

class Solution {
    public Node copyRandomList(Node head) {
        //1.先复制链表,不处理random指针
        Node chead = new Node(0);
        Node ccur = chead;
        Node cpre = null;

        Node cur = head;

        while (cur != null) {
            cpre = ccur;
            ccur = new Node(cur.val);
            cpre.next = ccur;
            cur = cur.next;
        }

        chead = chead.next;
		//2.同时遍历两个两个链表
        ccur = chead;
        cur = head;
        while (cur != null) {
            Node ran = cur.random;
            Node c1 = head;
            //3.确定原链表中节点random指向节点的索引值
            int i = 0;
            while (c1 != ran) {
                c1 = c1.next;
                i++;
            }
			//4.让复制链表中的节点的random指向相同索引位置的节点
            Node c2 = chead;
            for (int j = 0; j < i; j++) {
                c2 = c2.next;
            }
            ccur.random = c2;

            cur = cur.next;
            ccur = ccur.next;
        }
		//5.复制完成
        return chead;
    }
}

解法二:回溯+哈希表

思路

我们从头节点开始复制,val值直接复制即可,而next和random节点还没有创建,所以我们需要创建next和random节点,创建next和random节点继续重复这个过程即可。

但是仍然有一个问题,就是random指针的指向是随机的,多个random指针有可能指向同一个节点,所以我们需要用一个哈希表来存储已经创建了的节点,并在每次给next和random指针赋值前检查所指向的节点是否已经创建了,如果没有,我们就递归执行直到节点已经创建或者为null,然后回溯,直到所有节点都创建完成。至此,复杂链表的复制就完成了。

函数设计:

  • 基线条件:节点为null或者已经创建了
  • 递归条件:节点还没有创建

代码

class Solution {
    HashMap<Node,Node> nodeCache = new HashMap<>();
    public Node copyRandomList(Node head) {
        if (head==null) return null;
        while(!nodeCache.containsKey(head)){
            Node newHead = new Node(head.val);
            nodeCache.put(head,newHead);
            newHead.next = copyRandomList(head.next);
            newHead.random = copyRandomList(head.random);
        }
        return nodeCache.get(head);
    }
}