题目: 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
思路:
解法一:以空间换时间。整个过程分两步:首先遍历原链表,创建复制结点,并完成复制节点的val、next域的赋值,此过程中建立一个Map,存储原节点和其复制节点的映射关系。然后第二次遍历原链表,完成链表中节点的random域赋值,这一过程使用前一步的Map,在O(1)时间内找到该节点的random节点。
代码实现(已在牛客网AC):
import java.util.HashMap;
public class Solution {
public RandomListNode Clone(RandomListNode pHead)
{
if(pHead == null)
return null;
RandomListNode node = pHead;
int length = 0;
while(node != null){
length++;
node = node.next;
}
//建立原节点和复制节点的映射关系
HashMap<RandomListNode, RandomListNode> map = new HashMap<>(length);
RandomListNode[] copyList = new RandomListNode[length];
node = pHead;
for(int i = 0; i < length; i++){
copyList[i] = new RandomListNode(node.label);
map.put(node,copyList[i]);
node = node.next;
}
node = pHead;
int i;
for(i = 0; i < length-1; i++)
{
copyList[i].next = copyList[i+1];
//复制节点的random应该指向HashMap中node.random的映射
copyList[i].random = map.get(node.random);
node = node.next;
}
copyList[i].next = null;
copyList[i].random = map.get(node.random);
return copyList[0];
}
}
时空复杂度:通过建立哈希映射,将时间复杂度降低到O(n)。
解法二:在不使用辅助空间的情况下实现O(n)的时间效率。解法分三步:
1)根据原始链表的每个节点N创建对应的N’,并把每个N’链接在N的后面(考查链表的插入操作)。
2)设置复制节点的random。假设原链表上节点N的random指向节点S,由于复制节点N’是N的next指向的节点,故N’的random应该指向S的next指向的节点。
3)将前两步所形成的长链表分为两个链表。
代码实现(已在牛客网AC):
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
public class Solution {
public RandomListNode Clone(RandomListNode pHead)
{
GenerateCopyList(pHead);
ConnectSiblingNodes(pHead);
return ReconnectNodes(pHead);
}
//第一步
private void GenerateCopyList(RandomListNode pHead){
if(pHead == null)
return;
RandomListNode node = pHead;
while(node != null){
RandomListNode copy = new RandomListNode(node.label);
copy.next = node.next;
node.next = copy;
node = copy.next;
}
}
private void ConnectSiblingNodes(RandomListNode pHead){
if(pHead == null)
return;
RandomListNode node = pHead;
while(node != null){
RandomListNode pCloned = node.next;
if(node.random != null){
pCloned.random = node.random.next;
}
node = pCloned.next;
}
}
private RandomListNode ReconnectNodes(RandomListNode pHead){
// 多设一个表头指针,专门用来返回
RandomListNode cloneHead = null;
RandomListNode cloneNode = null;
RandomListNode node = pHead;
if(node != null){
cloneHead = node.next;
cloneNode = node.next;
node.next = cloneNode.next;
node = node.next;
}
// 注意cloneNode和node都是一次移动两个节点
while(node != null){
cloneNode.next = node.next;
cloneNode = cloneNode.next;
node.next = cloneNode.next;
node = node.next;
}
return cloneHead;
}
}