剑指Offer 复杂链表的复制

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

本题在《剑指offer》里面提供了除了直接复制两种指针之外的两种思路,下面分别讨论。

第一种:使用一个哈希表存储节点信息,是一种用空间换时间的方法,时间复杂度为O(n)。

首先在新的链表里开始复制节点的Next信息,在复制Next信息的时候,建立一个哈希表,哈希表的键为旧链表里面的节点,值为新链表里面的节点,如:将旧链表的节点node赋值给新链表的node_1后,给哈希表添加一个键值对:nodeMap[node] = node_1。
这样做的好处是在第一次复制完Next信息之后,哈希表也建立好了,在复制random节点时,由于有哈希表的键值对,因此,找到node_1的random的时间复杂度为O(1),即:node_1->random = nodeMap[node->random]。
具体代码如下:
class Solution {
private:
	RandomListNode * result;
	map<RandomListNode*, RandomListNode*> nodeMap;
public:
	RandomListNode * cloneNext(RandomListNode* pHead) {
		RandomListNode *temp, *pHeadNew = pHead, *tempNew, *resultTemp;
		temp = new RandomListNode(0);
		resultTemp = temp;
		// 第一次复制,对map进行赋值
		while (pHeadNew != NULL) {

			tempNew = new RandomListNode(0);
			tempNew->label = pHeadNew->label;
			temp->next = tempNew;
			temp = temp->next;

			nodeMap[pHeadNew] = tempNew;
			pHeadNew = pHeadNew->next;
		}
		temp = resultTemp->next;
		// 第二次复制,对random指针复制
		while (pHead != NULL) {
			if (pHead->random != nullptr) {
				//cout << pHead->label << " " << pHead->random->label << endl;
				temp->random = nodeMap[pHead->random];
				//cout << temp->random->label << endl;
			}
			else temp->random == nullptr;
			pHead = pHead->next;
			temp = temp->next;
		}
		return resultTemp->next;
	}
	
	RandomListNode * Clone(RandomListNode* pHead)
	{
		if (pHead == NULL) return result;
		else {
			return cloneNext(pHead);
		}
	}
};

书中介绍的第二种方法:主要分为三步:首先:将链表中的节点都复制一份,并把相应的复制之后的节点连接在原来节点后面,第二步:复制random指针,由于之前的复制,那么假如A点的random指针指向C点,那么A后面的A’点的random指针必然指向C点后面的C’点,第三步:将这个链表中的点分开,偶数节点连接成一个新的链表,这个链表就是我们需要的链表。

具体代码如下:
class Solution {
private:
	RandomListNode * result;
	map<RandomListNode*, RandomListNode*> nodeMap;
public:
	
	RandomListNode * cloneNode(RandomListNode* pHead) {
		RandomListNode* pHeadNew = pHead;
		// 插入节点
		while (pHead != nullptr) {
			RandomListNode* temp = new RandomListNode(0);
			temp->label = pHead->label;
			RandomListNode* nextNode = pHead->next;
			pHead->next = temp;
			temp->next = nextNode;
			pHead =temp->next;
		}
		// 对节点的random指针赋值
		pHead = pHeadNew;
		while (pHead != nullptr) {
			RandomListNode*temp = pHead->random;
			if (temp != nullptr)
				pHead->next->random = temp->next;
			else
				pHead->next == nullptr;
			pHead = pHead->next->next;
		}
		
		return pHeadNew;
	}

	RandomListNode* ReconnentNode(RandomListNode* pHead) {
		RandomListNode* pNode = pHead;
		RandomListNode* pClonedHead = new RandomListNode(0);  // 0
		RandomListNode* pClonedNode = pClonedHead;
		
		do {
			pClonedNode->next = pNode->next;  // 1  将偶数节点连接在pClonedNode后面
			pClonedNode = pClonedNode->next;  // 2  将pClonedNode后面节点赋值给pClonedNode准备下一次赋值
			pNode->next = pClonedNode->next;  // 3  pNode的next赋值为pClonedNode的next,就是下一个奇数点
			pNode = pNode->next;			  // 4  pNode赋值成下一个奇数点
		} while (pNode!=nullptr);

		return pClonedHead->next;
	}
	RandomListNode * Clone(RandomListNode* pHead)
	{
		// show(pHead);
		cout << endl;
		if (pHead == nullptr) return result;
		RandomListNode*head =  cloneNode(pHead);
		return ReconnentNode(head);
	}
};

对于ReconnentNode函数,我画了个图在下面,看起来会清楚点

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值