《剑指offer》面试题26:复杂链表的复制

题目:请实现一个函数用于复制一个复杂链表。在复杂链表中,每个结点除了有一个next指针指向下一个结点外,还有一个sibling指向链表中的任意结点或者null。

方法一:时间O(n)。分为三个步骤。

  1. 在每一个结点后面复制一个只包含next指针不含sibling的相同的结点。一次遍历O(n)
  2. 复制结点的sibling指针,其中复制的结点指向的复制的结点。一次遍历O(n)
  3. 分割链表。一次遍历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;
}

猜你喜欢

转载自blog.csdn.net/qq_25024883/article/details/79643172
今日推荐