JAVA-广联达-复杂链表复制问题

题目

复杂链表指的是一个链表有若干个结点,每个结点有一个数据域用于存放数据,还有两个指针域,其中一个指向下一个节点,还有一个随机指向当前复杂链表中的任意一个节点或者是一个空结点。 如何对这样一个复杂链表复制产生一个新的复杂链表。

解题思路

第一种:首先复制next指针的节点,之后再复制random指针的节点.
在这里插入图片描述

第一种code

//假设头节点无数据,头结点所指的第一个节点是链表的第一个真正节点
public static RandomListNode copyMethod1(RandomListNode pHead) {
		// 判断链表是否为空
		if (pHead.next == null)
			return null;
		// 保存旧列表的第一个节点
		RandomListNode oldListNode = pHead.next;
		// 构建新链表的头结点
		RandomListNode head = new RandomListNode(-1);
		RandomListNode newListNode = head;
		// 遍历复制next链表1->2->3->4复制成1->2->3->4
		while (oldListNode != null) {
			RandomListNode temp = new RandomListNode(oldListNode.value);
			newListNode.next = temp;
			newListNode = newListNode.next;

			oldListNode = oldListNode.next;
		}

		// 复制随机节点,记录需要遍历的节点位置
		oldListNode = pHead.next;
		newListNode = head.next;
		while (oldListNode != null) {
			// 找到第一个节点的随机节点
			RandomListNode randomNode = oldListNode.random;
			// 当前存在随机节点
			if (randomNode != null) {
				// 新旧链表中的第一个节点
				RandomListNode oldTemp = pHead.next;
				RandomListNode newTemp = head.next;
				// 找到指定新节点中需要查找的随机指针的节点
				while (oldTemp != randomNode) {
					oldTemp = oldTemp.next;
					newTemp = newTemp.next;
				}
				// 确定新节点的随机指针
				newListNode.random = newTemp;
			}
			oldListNode = oldListNode.next;
			newListNode = newListNode.next;
		}
		return head;
	}

第二种:通过map来实现或者通过数组来实现 map实现:
1、设置一个HashMap用来存储 每一个 链表的节点,<key,value> 分别为原链表节点、新链表节点;
2、复制,第一步顺着next依次复制,第二步就是复制random指针
3、如果原链表random指针不为空则从map中取出来,然后设置对应新链表的节点,这样空间复杂度为O(n), 时间复杂度为O(n)。 数组实现:
1、设置两个数组,oldNodeArr,newNodeArr 按照next的顺序保存新旧节点;
2、顺着next依次复制,并填充oldNodeArr,newNodeArr两个数组;
3、填充新链表的random节点,依据原链表某个节点的random节点,在oldNodeArr中找到指定的random节点下标index即可从newNodeArr[index]得到新节点的随机节点。
在这里插入图片描述

第二种code

//假设头节点无数据,头结点所指的第一个节点是链表的第一个真正节点
public static RandomListNode copyMethod2(RandomListNode pHead) {
		if (pHead.next == null) {
			return null;
		}
		RandomListNode oldListNode = pHead.next;
		RandomListNode head = new RandomListNode(-1);
		RandomListNode newListNode = head;
		// <oldListNode,newListNode>
		HashMap<RandomListNode, RandomListNode> hash = new HashMap<RandomListNode, RandomListNode>();
		// 复制节点并连接next
		while (oldListNode != null) {
			RandomListNode newNode = new RandomListNode(oldListNode.value);
			hash.put(oldListNode, newNode);
			newListNode.next = newNode;
			newListNode = newListNode.next;
			oldListNode = oldListNode.next;
		}
		// 定位旧链表的首个节点
		oldListNode = pHead.next;
		while (oldListNode != null) {
			if (oldListNode.random != null) {
				// 得到新的节点
				RandomListNode value = hash.get(oldListNode);
				// 得到新的节点需要指向的随机节点
				RandomListNode random = hash.get(oldListNode.random);
				value.random = random;
			}
			oldListNode = oldListNode.next;
		}
		return head;
	}

第三种:不用辅助空间实现O(n)的解法
1、顺着next走的时候我们复制出来的新节点紧接着插入对应的旧节点后面;
2、复制random指针;
3、将生成的链表的奇数位置的节点拆出来链接在一起得到原链表,偶数位置的节点拆出来链接在一起就是我们需要的复制链表。
在这里插入图片描述

第三种code

//假设头节点无数据,头结点所指的第一个节点是链表的第一个真正节点
public static RandomListNode copyMethod3(RandomListNode pHead) {
		if (pHead.next == null) {
			return null;
		}
		// 复制并将新的节点插入原节点之后
		RandomListNode oldListNode = pHead.next;
		while (oldListNode != null) {
			RandomListNode temp = new RandomListNode(oldListNode.value);
			temp.next = oldListNode.next;
			oldListNode.next = temp;
			oldListNode = temp.next;
		}
		// 复制random指针
		oldListNode = pHead.next;
		while (oldListNode != null) {
			if (oldListNode.random != null) {
				//新节点.random = 旧节点.random.next
				oldListNode.next.random = oldListNode.random.next;
			}
			oldListNode = oldListNode.next.next;
		}
		// 拆分链表
		oldListNode = pHead.next;
		//新链表头结点
		RandomListNode head = new RandomListNode(-1);
		head.next = oldListNode.next;
		RandomListNode newListNode = head.next;
		// 这个部分需要注意一下
		while (newListNode.next != null) {
			oldListNode.next = newListNode.next;
			oldListNode = oldListNode.next;
			newListNode.next = oldListNode.next;
			newListNode = newListNode.next;
		}
		// 最后将原来链表的尾部设置为null
		oldListNode.next = null; 
		return head;
	}

猜你喜欢

转载自blog.csdn.net/CTPeng/article/details/82759391
今日推荐