《剑指offer》面试题35:复杂链表的复制

题目:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)


节点定义如下:

struct RandomListNode
{ 
	int value; 
	RandomListNode* next; 
	RandomListNode* random ; 
	RandomListNode():next(nullptr),random (nullptr) { } 
}; 
思路一:

我们分为两步:
1.复制原始链表上每个节点N创建N*,然后把这些穿件出来的节点用next连接起来。同时我们把(N,N*)的配对信息放到一个哈希表中;
2.设置复制链表上每个节点的rand。
时间复杂度O(n),空间复杂度O(n)。

java参考代码如下:

    public static class Node{
        int value;
        Node next;
        Node rand;
        public Node(int val){
            this.value=val;
            this.next=null;
            this.rand=null;
        }
    }
    //
    public static Node copyListWithRand1(Node head){
        if(head==null) return null;
        HashMap<Node,Node> map=new HashMap<>();
        Node cur=head;
        while (cur!=null){
            map.put(cur,new Node(cur.value));//放入的是遍历到的节点指针和副本。
            cur=cur.next;
        }
        cur=head;
        while (cur!=null){
            map.get(cur).next=map.get(cur.next);
            map.get(cur).rand=map.get(cur.rand);
            cur=cur.next;
        }
        return map.get(head);
    }
思路二:

分三步:
第一步:复制每个节点,如:复制节点A得到A1,将A1插入节点A后面;
第二步:遍历链表,A1->random = A->random->next;
第三步:将链表拆分成原链表和复制后的链表。

基于以上思路,Java参考代码如下:

package chapter4;

import java.util.HashMap;

public class P187_CopyComplexList {
    public static class Node{
        int value;
        Node next;
        Node rand;
        public Node(int val){
            this.value=val;
            this.next=null;
            this.rand=null;
        }
    }
  
    public static void printRandLinkedList(Node head) {
        Node cur = head;
        System.out.print("order: ");
        while (cur != null) {
            System.out.print(cur.value + " ");
            cur = cur.next;
        }
        System.out.println();
        cur = head;
        System.out.print("rand:  ");
        while (cur != null) {
            System.out.print(cur.rand == null ? "- " : cur.rand.value + " ");
            cur = cur.next;
        }
        System.out.println();
    }
    public static Node copyListWithRand2(Node head) {
        if (head == null) {
            return null;
        }
        Node cur = head;
        Node next = null;
        // copy node and link to every node
        while (cur != null) {
            next = cur.next;
            cur.next = new Node(cur.value);
            cur.next.next = next;
            cur = next;
        }
        cur = head;
        Node curCopy = null;
        // set copy node rand
        while (cur!=null){
            cur.next.rand=cur.rand!=null?cur.rand.next:null;//注意 cur.rand为空的情况
            cur=cur.next.next;
        }
        Node res = head.next;
        cur = head;
        // split
        while (cur != null) {
            next = cur.next.next;
            curCopy = cur.next;
            cur.next = next;
            curCopy.next = next != null ? next.next : null;
            cur = next;
        }
        return res;
    }
    public static void main(String[] args) {
        Node head = null;
        Node res1 = null;
        Node res2 = null;
        printRandLinkedList(head);
        res1 = copyListWithRand1(head);
        printRandLinkedList(res1);
        res2 = copyListWithRand2(head);
        printRandLinkedList(res2);
        printRandLinkedList(head);
        System.out.println("=========================");

        head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(3);
        head.next.next.next = new Node(4);
        head.next.next.next.next = new Node(5);
        head.next.next.next.next.next = new Node(6);

        head.rand = head.next.next.next.next.next; // 1 -> 6
        head.next.rand = head.next.next.next.next.next; // 2 -> 6
        head.next.next.rand = head.next.next.next.next; // 3 -> 5
        head.next.next.next.rand = head.next.next; // 4 -> 3
        head.next.next.next.next.rand = null; // 5 -> null
        head.next.next.next.next.next.rand = head.next.next.next; // 6 -> 4

        printRandLinkedList(head);
        res1 = copyListWithRand1(head);
        printRandLinkedList(res1);
        res2 = copyListWithRand2(head);
        printRandLinkedList(res2);
        printRandLinkedList(head);
        System.out.println("=========================");

    }
}

注意点见代码注解部分。

基于以上思路,C++参考代码如下:

class Solution 
{ 
public: 
	RandomListNode* Clone(RandomListNode* pHead) 
	{ 
		CloneNodes(pHead); 
		ConnectRandomNodes(pHead); 
		return ReconnectNodes(pHead); 
	} 

	//第一步 
	void CloneNodes(RandomListNode* pHead)
	{ 
		RandomListNode* pNode = pHead; 
		while(pNode != nullptr)
		{ 
			RandomListNode* pCloned = new RandomListNode(pNode->label); 
			pCloned->next = pNode->next; 
			pCloned->random = nullptr; 
			pNode->next = pCloned; 
			pNode = pCloned->next; 
		} 
	} 

	//第二步 
	void ConnectRandomNodes(RandomListNode* pHead)
	{ 
		RandomListNode* pNode = pHead; 
		while(pNode != nullptr)
		{ 
			RandomListNode* pCloned = pNode->next; 
			if(pNode->random != nullptr)
			{ 
				pCloned->random = pNode->random->next; 
			} 
			pNode = pCloned->next; 
		} 
	} 

	//第三步 
	RandomListNode* ReconnectNodes(RandomListNode* pHead)
	{ 
		RandomListNode* pNode = pHead; 
		RandomListNode* pClonedHead = nullptr; 
		RandomListNode* pClonedNode = nullptr; 
		if(pNode != nullptr)
		{ 
			pClonedHead = pClonedNode = pNode->next; 
			pNode->next = pClonedNode->next; 
			pNode = pNode->next; 
		} 
		while(pNode != nullptr)
		{ 
			pClonedNode->next = pNode->next; 
			pClonedNode = pClonedNode->next; 
			pNode->next = pClonedNode->next; 
			pNode = pNode->next; 
		} 
		return pClonedHead; 
	} 
};
测试用例:

a.功能测试(节点中的random指向节点自身;两个节点的random形成环状结构;链表中只有一个节点)。
b.特殊输入测试(指向链表头节点的指针为nullptr指针)。

参考:

https://blog.csdn.net/Koala_Tree/article/details/79430560

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值