题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点)。
结点的定义已给出
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
举个例子,更容易明白
下图是一个含有5个结点的该类型复杂链表。图中实线箭头表示m_pNext指针,虚线箭头表示m_pSibling指针。为简单起见,指向NULL的指针没有画出
思路:不考虑时间复杂度,把复制分成两步,第一步复制结点并用m_pNext链接,第二步设置每个结点的m_pSibling。对每个结点,从头开始遍历原始链表,找到每个结点m_pSibling指向的结点S(记下从头开始遍走过的步数s),则复制链表结点的m_pSibling指向的结点距离头结点也是s步。
根据以上思路,编码
/**
*
*/
package com.su.biancheng;
/**
* @title CloneListO_n2.java
* @author Shuai
* @date 2016-4-28下午9:51:12
*/
public class CloneListO_n2 {
public static class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
//O(N^2)
public static RandomListNode Clone(RandomListNode pHead){
if(pHead==null)
return null;
RandomListNode pNode=pHead;
RandomListNode pCloned=new RandomListNode(pNode.label);//create a new list HeadNode
RandomListNode p1=pNode;
RandomListNode p2=pCloned;
while(p1.next!=null){
p2.next=new RandomListNode(p1.next.label);
p1=p1.next;
p2=p2.next;
}
p1=pNode;
p2=pCloned;
while(p1!=null){
if(p1.random!=null){
//copy m_pSibling ,traverse list from head to tail,find SNode
RandomListNode temp=pNode;
RandomListNode temp2=pCloned;
while(temp!=p1.random&&temp.next!=null){
temp=temp.next;
temp2=temp2.next;
}
p2.random=temp2;
}
p1=p1.next;
p2=p2.next;
}
return pCloned;
}
public static void main(String[] args){
RandomListNode pHead = new RandomListNode(1);
RandomListNode node1 = new RandomListNode(2);
RandomListNode node2 = new RandomListNode(3);
RandomListNode node3 = new RandomListNode(4);
RandomListNode node4 = new RandomListNode(5);
pHead.next = node1;
node1.next = node2;
node2.next = node3;
node3.next = node4;
pHead.random = node2;
node2.random = node4;
node3.random = node1;
System.out.println(Clone(pHead).random.label);
}
}
上面的时间主要花费在找m_pSibling上,在这方面做优化。还是两步:第一步,复制原始链表结点N到新创建结点N’,并将复制后的结点用next链接,同时把<N,N'>
用hashMap存放;第二步,设置链表结点的random。这个时候不用每次从头遍历原始链表确定random,可以直接从hashMap中取出random对应的random’。
改进后的时间算法为O(2n),代码如下
/**
*
*/
package com.su.biancheng;
import java.util.HashMap;
/**
* @title CloneListO_2n_map.java
* @author Shuai
* @date 2016-4-29下午8:32:59
*/
public class CloneListO_2n_map {
public static class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
//O(2N)
public static RandomListNode Clone(RandomListNode pHead){
if(pHead==null)
return null;
HashMap<RandomListNode,RandomListNode> map = new HashMap<RandomListNode,RandomListNode>();
RandomListNode pNode=pHead;
RandomListNode pCloned=new RandomListNode(pNode.label);//create a new list HeadNode
RandomListNode p1=pNode;
RandomListNode p2=pCloned;
map.put(p1, p2);
while(p1.next!=null){
p2.next=new RandomListNode(p1.next.label);
map.put(p1.next, p2.next);
p1=p1.next;
p2=p2.next;
}
p1=pNode;
p2=pCloned;
while(p1!=null){
if(p1.random!=null){
//copy m_pSibling ,according to hashMap's key-value ,find m_pSibling' with m_pSibling
p2.random=map.get(p1.random);
}
p1=p1.next;
p2=p2.next;
}
return pCloned;
}
public static void main(String[] args){
RandomListNode pHead = new RandomListNode(1);
RandomListNode node1 = new RandomListNode(2);
RandomListNode node2 = new RandomListNode(3);
RandomListNode node3 = new RandomListNode(4);
RandomListNode node4 = new RandomListNode(5);
pHead.next = node1;
node1.next = node2;
node2.next = node3;
node3.next = node4;
pHead.random = node2;
node2.random = node4;
node3.random = node1;
System.out.println(Clone(pHead).random.label);
}
}
用hashMap存储,实际上是用空间换时间。如何不利用辅助空间实现O(n)的时间?
第一步:根据原始结点N创建新的结点N’,但是把N’连在N的next,如下图
第二步:设置random。N的random指向S,N’的random指向S’,N的next指向N’,则S的next指向S’。总之N’的random指向S的next。如下图
第三步,拆分。把以上得到的长链表,拆分成原始链表和复制链表。奇数位置用next连起来是原始链表。偶数位置连起来是复制链表。如下图
代码实现如下:
/**
*
*/
package com.su.biancheng;
import java.util.HashMap;
import com.su.biancheng.CloneListO_2n_map.RandomListNode;
/**
* @title CloneListO_2n_1.java
* @author Shuai
* @date 2016-4-29下午9:00:34
*/
public class CloneListO_2n_1 {
public static class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
//O(2N),S(1)
public static RandomListNode Clone(RandomListNode pHead){
if(pHead==null)
return null;
RandomListNode pNode=pHead;
RandomListNode p1=pNode;
//1 copy per node to node.next,such as, pCloned=pNode.next
while(p1!=null){
RandomListNode p2=new RandomListNode(p1.label);//create a new Node copy of original node
p2.next=p1.next;
p2.random=null;
//pCloned add to between p1 and p1.next
p1.next=p2;
p1=p2.next;
}
//2 traverse list,make N'.random=N.random.next
p1=pNode;
while(p1!=null){
RandomListNode p2=p1.next;
if(p1.random!=null){
p2.random=p1.random.next;
}
p1=p2.next;
}
//3 break up the list,odd position using next is original list,even position using next is copy list
RandomListNode pCloned=pHead.next;
p1=pHead;
while(p1.next!=null){
RandomListNode temp=p1.next;
p1.next=temp.next;
p1=temp;
}
return pCloned;
}
public static void main(String[] args){
RandomListNode pHead = new RandomListNode(1);
RandomListNode node1 = new RandomListNode(2);
RandomListNode node2 = new RandomListNode(3);
RandomListNode node3 = new RandomListNode(4);
RandomListNode node4 = new RandomListNode(5);
pHead.next = node1;
node1.next = node2;
node2.next = node3;
node3.next = node4;
pHead.random = node2;
node2.random = node4;
node3.random = node1;
System.out.println(Clone(pHead).random.label);
}
}