[路飞]_每天刷leetcode_06(复制带随机指针的链表)

这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

 今天我们来看一道链表相关的题目,复制随机指针的链表,要求是深拷贝。对普通链表深拷贝是容易的,但是对有随机指针的链表进行深拷贝要如何实现呢?

复制带随机指针的链表

题目

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。 random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。 你的代码 只 接受原链表的头节点 head 作为传入参数

A linked list of length n is given such that each node contains an additional random pointer, which could point to any node in the list, or null.

Construct a deep copy of the list. The deep copy should consist of exactly n brand new nodes, where each new node has its value set to the value of its corresponding original node. Both the next and random pointer of the new nodes should point to new nodes in the copied list such that the pointers in the original list and copied list represent the same list state. None of the pointers in the new list should point to nodes in the original list.

For example, if there are two nodes X and Y in the original list, where X.random --> Y, then for the corresponding two nodes x and y in the copied list, x.random --> y.

Return the head of the copied linked list.

The linked list is represented in the input/output as a list of n nodes. Each node is represented as a pair of [val, random_index] where:

val: an integer representing Node.val random_index: the index of the node (range from 0 to n-1) that the random pointer points to, or null if it does not point to any node. Your code will only be given the head of the original linked list.

Example:

img


Input: head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
Output: [[7,null],[13,0],[11,4],[10,2],[1,0]]
复制代码

e2.png

Input: head = [[1,1],[2,1]]
Output: [[1,1],[2,1]]
复制代码
Input: head = []
Output: []
Explanation: The given linked list is empty (null pointer), so return null.
复制代码

Constraints:

  • 0 <= n <= 1000
  • -10000 <= Node.val <= 10000
  • Node.random is null or is pointing to some node in the linked list.

思考线


解题思路

思路1

由于有 random 指针的关系,所以我们复制的时候不是很好复制。在这里我首先想到,如果先不管random指针,那就很好实现复制了。

但是第二遍怎么复制random指针却是个难题。实现了好久没有得到解法。于是我看了别人怎么做的。

要是按照这个思路走是 可以走通的,不过我们要做一些变通。

  1. 在每个节点后面插入一个复制节点,这样奇数表示的是原链表,偶数为复制链表。第一遍不复制random指针。
  2. 第二遍复制random指针的方法为 [原节点].next.random = [原节点].random.next. 这样就可以完美的把 复制链表中的random指针正确的指向复制节点。
  3. 在分离出原节点和复制节点即可。

按照上面的思路 我实现了以下代码

思路1代码实现

/**
 * @param {Node} head
 * @return {Node}
 */
var copyRandomList = function (head) {      
		if(!head) return head;
    let olist = head;
    // round 1
    while (olist) {
        olist.next = new Node(olist.val, olist.next);
        olist = olist.next.next;
    }
    // round 2
    olist = head;
    while (olist) {
        if (olist.random) {
            olist.next.random = olist.random.next;
        }

        olist = olist.next.next;
    }

    // round 3

    olist = head;
    let head2 = head.next;
    let nlist = head2;
    while (olist) {
        olist.next = nlist.next;
        if (nlist.next) {
            nlist.next = olist.next.next;
            
        }
        olist = olist.next;
        nlist = nlist.next;
    }
    return head2;
}
复制代码

思路2

在 ES6中我们有一种结构叫做 Map, 这个接口可以实现对象作为key值,那么我们可以用一个hashMap 来保存 在复制过程中遇到的节点, 其中key为原节点,value为复制节点,这样可以很好的规避掉random指向节点不明的问题,因为每个节点都被我们记录在了hashMap中。

这样只需要遍历一遍就可以了。

下面是代码实现

/**
 * @param {Node} head
 * @return {Node}
 */
var copyRandomList = function (head) {    
		if(!head) return head;
    const map = new Map();
    let olist = head;
    const head1 = new Node(head.val);
    let nlist = head1;
    while(olist) {
        const next = olist.next;
        const random = olist.random;
        if(!map.get(olist)) map.set(olist, nlist)
        if(map.get(next)) {
            nlist.next = map.get(next)
        } else {
            next && nlist.next = new Node(next?.val);
            map.set(next, nlist.next || null)
        }
        if(map.get(random)) {
            nlist.random = map.get(random)
        } else {
            random && nlist.random = new Node(random.val)
            map.set(random, nlist.random || null)
        }
        olist = olist.next;
        nlist = nlist.next;
    }

    return head1;
}
复制代码

OK,这就是我们今天leetcode刷题的全部内容,我们下期见。

猜你喜欢

转载自juejin.im/post/7032249464655970312