随机指针链表深复制

来源:互联网 发布:swift model数组 编辑:程序博客网 时间:2024/06/03 19:06

题目描述[微软苏州]

一条带随机指针的链表,对于每个节点,除了next指针指向下一个节点以外,还带一个randNext指针指向链表中任何一个节点或空。求对这个链表进行深复制,即复制出的链表和原来链表具有完全相同的结构,但是与原链表完全无关。

分析1

此题难点在于新建链表节点的randNext不能立即在新链表中找到指向,如果要记录randNext指向节点相对于自身的位置,那么每个节点都需要有一个遍历计数过程,时间复杂度为O(n2)。因此如何立即找到randNext指向的节点就成为了关键步骤。
使用链表的问题在于查找过程需要遍历,从而导致了效率低下,所以可以想到使用哈希来快速查找所需要的节点。这里HashMap记录旧节点和新节点之间的映射关系,一旦得到了一个旧节点,就可以立刻找到新节点,查找的复杂度为O(1)。这样需要两次遍历就可以将新的链接关系建立起来了,一次建立HashMap,一次复制链接。

代码1

static Node copyWithHash(Node headNode) {    Map<Node, Node> map = new HashMap<>();    Node oldNode = headNode;    // 建立新节点与原节点的映射    while (oldNode != null) {        map.put(oldNode, new Node(oldNode.data + 100));// 测试        oldNode = oldNode.next;    }    oldNode = headNode;    Node newHeadNode = null;    Node newNode = null;    // 利用映射将旧链接关系复制到新链接关系    while (oldNode != null) {        newNode = map.get(oldNode);        newNode.next = map.get(oldNode.next);        newNode.randNext = map.get(oldNode.randNext);// get(null)仍返回null        if (newHeadNode == null) newHeadNode = newNode;        oldNode = oldNode.next;    }    return newHeadNode;}

分析2

使用HashMap的空间复杂度为O(n),能否不用哈希就能立刻找到新节点呢?最简单的方法就是将新节点插入在旧节点之后,这样只需要旧节点的next就可以找到新节点了。只是复制过程复杂一些,需要三次遍历才可以:第一次插入新节点到原链表中,即newNode.next = oldNode.next; oldNode.next = newNode,第二次复制链接关系,即newNode.randNext = oldNode.randNext.next,最后一次从原链表分离出新链表,即oldNode.next = newNode.next; newNode.next = newNode.next.next

代码2

static Node copyInsertion(Node headNode) {    // 第一遍将新节点链接到旧节点next后,并链接到下一个旧节点    Node oldNode = headNode;    while (oldNode != null) {        Node newNode = new Node(oldNode.data + 100);// 测试        newNode.next = oldNode.next;        oldNode.next = newNode;        oldNode = newNode.next;    }    // 第二遍将旧节点randNext链接关系复制到新节点上    oldNode = headNode;    while (oldNode != null) {        Node newNode = oldNode.next;        if (oldNode.randNext != null){            newNode.randNext = oldNode.randNext.next;        }        oldNode = newNode.next;    }    // 第三遍将新节点与旧节点分离开    Node newHeadNode = null;    oldNode = headNode;    while (oldNode != null) {        Node newNode = oldNode.next;        oldNode.next = newNode.next;        oldNode = oldNode.next;        if (oldNode != null) newNode.next = oldNode.next;        if (newHeadNode == null) newHeadNode = newNode;    }    return newHeadNode;}

测试

import java.util.HashMap;import java.util.Map;import java.util.Random;public class RandLinked {    static class Node {        int data;        Node next = null, randNext = null;        Node(int data) {            this.data = data;        }    }    static Node buildRandLinked(int[] data) {        int length = data.length;        Map<Integer, Node> map = new HashMap<>(length);        for (int i : data) {            map.put(i, new Node(i));        }        int[] randIndex = new int[length];        Random random = new Random();        for (int i = 0; i < length; i++) {            randIndex[i] = random.nextInt(length);        }        Node headNode = map.get(data[0]);        Node tmpNode = null;        for (int i = 0; i < length - 1; i++) {            tmpNode = map.get(data[i]);            tmpNode.next = map.get(data[i + 1]);            if (randIndex[i] % 4 == 0)                tmpNode.randNext = null;            else                tmpNode.randNext = map.get(data[randIndex[i]]);        }        return headNode;    }    static void printRandLinked(Node headNode) {        Node tmpNode = headNode;        while (tmpNode != null) {            System.out.print(tmpNode.data + " -> ");            System.out.println(tmpNode.randNext == null ? null : tmpNode.randNext.data);            tmpNode = tmpNode.next;        }    }    public static void main(String[] args) {        Node headNode = buildRandLinked(new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9});        printRandLinked(headNode);        System.out.println("-----------");        printRandLinked(copyInsertion(headNode));    }} /* result0 -> null1 -> 22 -> 33 -> 94 -> 65 -> null6 -> 77 -> 98 -> 69 -> null-----------100 -> null101 -> 102102 -> 103103 -> 109104 -> 106105 -> null106 -> 107107 -> 109108 -> 106109 -> null*/
0 0