题目:
请实现函数 public Node clone(Node pHead),复制一个复杂链表。在复杂链表中,每个结点除了有一个Next指针指向下一个结点外,还有一个random指向链表中的任意结点或者NULL。结点的定义如下:
public class Node {
public int val;
public Node next;
public Node random;
public Node (int val){
this.val = val;
}
}
上图是一个包含四个复杂结点的复杂链表,实现代表next指针,虚线代表random指针。
第一思路
复杂链表的复制可以分为两个部分,第一步就是将全部结点复制,并用next指针链接起来,第二布是把每个结点的random指针指向它对应的复制结点。这样的话第一步的事件复杂度为便利一次单链表的时间复杂度即为:O(n),第二部则需要首先便利每一个random指针,找到其指向的对应位置,然后便利复制结点找到当前random应该指向的位置,这样的话时间复杂度为O(n2),这样的话整个复制算法的时间复杂度为O(n2)。
优化思路
我们可以在复制结点的时候把,A和A`以key和value来存储进一个Map中,这样在寻找random指向位置的时候就可以通过Map.get()方法来直接获取到复制结点的random应该指向的结点。不过这样做事以O(n)的空间来换取了O(n)的时间。
代码实现
public static Node cloneNode(Node pHead){
if (pHead == null){
return null;
}
HashMap<Node,Node> nodeHashMap = new HashMap<>();
Node pCloneHead = new Node(pHead.val);
Node pNode = pHead;
Node pCloneNode = pCloneHead;
nodeHashMap.put(pNode,pCloneNode);
while (pNode.next != null){
pCloneNode.next = new Node(pNode.next.val);
pNode = pNode.next;
pCloneNode = pCloneNode.next;
nodeHashMap.put(pNode, pCloneNode);
}
pNode = pHead;
pCloneNode = pCloneHead;
while (pCloneNode != null){
pCloneNode.random = nodeHashMap.get(pNode.random);
pNode = pNode.next;
pCloneNode = pCloneNode.next;
}
return pCloneHead;
}
总结
通过HashMap的特性,来以O(n)的空间复杂度来换取了O(N2)的时间复杂度变为O(n)。
最优解法
不用O(n)的空间复杂度来实现O(n)的时间效率。
第一步:让仍然是根据原始链表的每个结点N创建对应的N’。不过我们把N’链接在N的后面。
第二步:设置复制出来的结点的random 。原始链表上的A的random 指向结点C,那么其对应复制出来的A’是A的next指向的结点,同样C’也是C的m_pNext指向的结点。即A’ = A.next,A’.random = A.random .next;故像这样就可以把每个结点的random 设置完毕。
第三步:将这个长链表中源节点删除掉,这样便得到了复制后的复杂链表。
代码实现
//在每个结点后添加其复制后的结点
public static void clone(Node pHead){
Node pNode = pHead;
while (pNode != null){
Node pClone = new Node(pNode.val);
if(pNode.next != null){
pClone.next = pNode.next;
pClone.random = null;
pNode.next = pClone;
pNode = pClone.next;
}else {
pNode.next = pClone;
break;
}
}
}
//设置每个结点的random(注:m_pSibling为空结点不做修改)
public static void random(Node pHead){
Node pNode = pHead;
while (pNode != null){
Node pClone = pNode.next;
if(pNode.random != null){
pClone.random = pNode.random.next;
}
pNode = pClone.next;
}
}
//拆分链表
public static Node del(Node pHead){
Node pNode = pHead;
Node pCloneHead = null;
Node pCloneNode = null;
if (pNode != null){
pCloneHead = pCloneNode = pNode.next;
pNode.next = pCloneNode.next;
pNode = pNode.next;
}
while (pNode != null){
pCloneNode.next = pNode.next;
pCloneNode = pCloneNode.next;
pNode.next = pCloneNode.next;
pNode = pNode.next;
}
return pCloneHead;
}
public static Node zhenghe(Node pHead){
clone(pHead);
random(pHead);
return del(pHead);
}
总结
这个复制算法通过三次便利便将复制后的复杂链表得到了,这样的时间复杂度为O(n);