力扣 - 剑指Offer 35.复杂链表的复制
题目
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
示例 1:

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:

输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 3:

输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
示例 4:
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。
思路1
我们利用HashMap,key存储旧的链表,value存储新的链表,先将链表复制一份到Map中,然后再同步遍历来设置他的next和random指针。最后返回复制的链表的head即可。
代码实现
class Solution {
    public Node copyRandomList(Node head) {
        HashMap<Node, Node> map = new HashMap<>();
        //由于待会还要用到head,所以创建一个Node用指向head
        Node cur = head;
        //复制链表到HashMap中
        while (cur != null) {
            map.put(cur, new Node(cur.val));
            cur = cur.next;
        }
        cur = head;
        
        while (cur != null) {
            //设置next指向,将复制的链表连接起来
            map.get(cur).next = map.get(cur.next);
            //将复制的链表的random指向与原来链表同步
            map.get(cur).random = map.get(cur.random);
            cur = cur.next;
        }
        //获取map中head对应的value(即新链表)返回
        return map.get(head);
        
    }
}
思路2
分三步来解决:
- 先将每个结点复制,然后跟在原来结点的后面,并且连接起来
- 设置复制的结点的random指向和原来的链表的random指向一样
- 将链表分离即可。
代码实现
class Solution {
    public Node copyRandomList(Node head) {
        copy(head);
        randomDirect(head);
        return getResult(head);
        
    }
    
    //第一步:先将每个结点复制,然后跟在原来结点的后面
    public void copy(Node head) {
        //复制每个结点到当前结点的下一个结点
        while (head != null) {
            //克隆当前结点
            Node cloneNode = new Node(head.val);
            //获取下一个要复制的结点
            Node nextNode = head.next;
            //将复制的结点和原来的链表链接起来
            head.next = cloneNode;
            cloneNode.next = nextNode;
            //将head指向下一个要复制的结点
            head = nextNode;
        }
    }
    
    //第二步:设置复制的结点的random指向和原来的链表的random指向一样
    public void randomDirect(Node head) {
        while (head != null) {
            //获取原链表对应的复制的结点
            Node cloneNode = head.next;
            //如果是空的会就跳过,否则会触发空指针异常
            if (head.random != null) {
	            Node direct = head.random;
	            //必须要用next才能指向我们复制的结点,如果没有加next那么就会指向原来的结点,不合题意
    	        cloneNode.random = direct.next;
            }
            head = cloneNode.next;
        }
    }
    
    //第三步:将旧链表与新链表分离
    public Node getResult(Node head) {
        //如果输入的head为空,那么直接返回
        if (head == null) {
            return null;
        }
        //获取复制的链表的头结点
        Node cloneNode = head.next;
        Node cloneHead = head.next;
        //将head的下一个结点修改为原来链表的下一个结点,然后再将head指向它
        head.next = head.next.next;
        head = head.next;
        while (head != null) {
            cloneNode.next = head.next;
            cloneNode = cloneNode.next;
            //由于原来的链表顺序也不能修改,所以两个链表必须全部分离,不能有依赖
            head.next = head.next.next;
            head = head.next;
        }
        return cloneHead;
    }
}
    我走得很慢,但我从不后退!

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号