题目:请实现一个函数用于复制一个复杂链表。在复杂链表中,每个结点除了有一个next指针指向下一个结点外,还有一个sibling指向链表中的任意结点或者null。
方法一:时间O(n)。分为三个步骤。
- 在每一个结点后面复制一个只包含next指针不含sibling的相同的结点。一次遍历O(n)
- 复制结点的sibling指针,其中复制的结点指向的复制的结点。一次遍历O(n)
- 分割链表。一次遍历O(n),难点
注意:必须记录root的位置,即复制一个相同的head,最好不要动root,会影响调用。
下面代码每一个函数代表一个步骤。
public ComplexListNode clone(ComplexListNode root) {
cloneNodes(root);
connectSiblingNodes(root);
return reconnectNodes(root);
}
public void cloneNodes(ComplexListNode root) {
ComplexListNode head = root;
while (head != null) {
ComplexListNode clone = new ComplexListNode(head.val);
clone.next = head.next;
clone.sibling = null;
head.next = clone;
head = clone.next;
}
System.out.println("cloneNode done.");
}
public void connectSiblingNodes(ComplexListNode root) {
ComplexListNode head = root;
while (head != null) {
if (head.sibling != null) {
head.next.sibling = head.sibling.next;
}
head = head.next.next;
}
}
public ComplexListNode reconnectNodes(ComplexListNode root) {
ComplexListNode head = root;
ComplexListNode chead = null;
ComplexListNode croot = null;
if (root != null) {
chead = root.next;
croot = root.next;
head.next = chead.next;
head = head.next;
}
while (head != null) {
chead.next = head.next;
chead = chead.next;
head.next = chead.next;
head = head.next;
}
return croot;
}
方法二:
思路:声明一个空链表,第一次遍历填满next指针。第二次遍历填满sibling指针。必须注意的是因为sibling是随意的,比如4->2,所以每一个sibling必须从头开始遍历。时间O(n^2)
public ComplexListNode clone2(ComplexListNode root) {
if (root == null)
return null;
ComplexListNode head = root;
ComplexListNode croot = new ComplexListNode(root.val);
ComplexListNode chead = croot;
// 复制next指针
while (head.next != null) {
chead.next = new ComplexListNode(head.next.val);
chead = chead.next;
head = head.next;
}
// 复制sibling指针
head = root;
chead = croot;
while (head != null) {
if (head.sibling != null) {
// 此处不能直接用val的相等去判断是否是sibling,
// 可能链表中的节点存在相等的值
ComplexListNode tmp = root;
int k = 0;
while (tmp != head.sibling) {
k++;
tmp = tmp.next;
}
tmp = croot;
while (k > 0) {
tmp = tmp.next;
k--;
}
chead.sibling = tmp;
}
head = head.next;
chead = chead.next;
}
return croot;
}
方法三:
思路:用空间替代时间。使用哈希表,记录<head, clonehead>。通过sibling指针查找clonesibling,对sibling指针进行添加。
注意:不能用<head, head.sibling>,会导致时间为O(n)。
public ComplexListNode clone3(ComplexListNode root) {
if (root == null)
return null;
ComplexListNode head = root;
ComplexListNode croot = new ComplexListNode(root.val);
ComplexListNode chead = croot;
HashMap<ComplexListNode, ComplexListNode> map = new HashMap<ComplexListNode, ComplexListNode>();
while (head.next != null) {
chead.next = new ComplexListNode(head.next.val);
map.put(head, head.sibling);
chead = chead.next;
head = head.next;
}
head = root;
chead = croot;
while (head != null) {
if (head.sibling != null)
chead.sibling = new ComplexListNode(map.get(head).val);
chead = chead.next;
head = head.next;
}
return croot;
}