随机指针链表深复制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhufenghao/article/details/70308150

题目描述[微软苏州]

一条带随机指针的链表,对于每个节点,除了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));
    }
} /* result
0 -> null
1 -> 2
2 -> 3
3 -> 9
4 -> 6
5 -> null
6 -> 7
7 -> 9
8 -> 6
9 -> null
-----------
100 -> null
101 -> 102
102 -> 103
103 -> 109
104 -> 106
105 -> null
106 -> 107
107 -> 109
108 -> 106
109 -> null
*/

猜你喜欢

转载自blog.csdn.net/zhufenghao/article/details/70308150