前言:
今天这个题有些没想到,精神不怎么好。
题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
测试用例:
{1,2,3,4,5,3,5,#,2,#}
对应输出应该为:
{1,2,3,4,5,3,5,#,2,#}
分析:
首先对这个复杂链表进行分析,说这个链表复杂只是多出了一个称为random的特殊指针,它指向链表中任意一项。
首先想到的是复制原始链表上的每一个结点,并通过pNext连接起来;然后再设置每个结点的pSibling指针。但是这样有些暴力,因为若原链表中某个结点p的random指针指向结点q,那么就需要从头到尾遍历查找结点q。这样的算法复杂度为O(n^2),理论上应该有优化的可能。
方法一:在思考良久后采用哈希表将原始链表和复制链表对应起来,这样就会使查找random的时间从O(n)降到O(1)这样算法复杂度也会降到O(n),算是以空间换时间吧。
复制原链表上的每个结点p创建t,然后把这些创建出来的结点用link连接起来。同时把
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
public class Test1 {
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)
{
HashMap<RandomListNode, RandomListNode> hashMap = new HashMap<RandomListNode,RandomListNode>();
RandomListNode p = pHead;
RandomListNode link = new RandomListNode(0);
while (p!=null) {
RandomListNode cloneP = new RandomListNode(p.label);
hashMap.put(p, cloneP);
p = p.next;
link.next = cloneP;
link = cloneP;
}
Set<Entry<RandomListNode, RandomListNode>> set = hashMap.entrySet();
Iterator<Entry<RandomListNode, RandomListNode>> iterator = set.iterator();
while (iterator.hasNext()) {
Entry<RandomListNode, RandomListNode> next = iterator.next();
next.getValue().random = hashMap.get(next.getKey().random);
}
return hashMap.get(pHead);
}
}
}
方法二(转自https://blog.csdn.net/samjustin1/article/details/51920885):
package niuke.easy;
public class CloneComplexLinkedList {
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
public static void main(String[] args) {
}
public RandomListNode Clone(RandomListNode pHead) {
CloneList(pHead);
ConstructSibling(pHead);
return Split(pHead);
}
private RandomListNode Split(RandomListNode pHead) {
RandomListNode orign, cloneHead = null, clone = null;
orign = pHead;
if (orign != null) {
cloneHead = orign.next;
orign.next = cloneHead.next;
orign = cloneHead.next;
clone = cloneHead;
}
while (orign != null) {
RandomListNode temp = orign.next;
orign.next = temp.next;
orign = orign.next;
clone.next = temp;
clone = temp;
}
return cloneHead;
}
/**
*
* @param pHead
*/
private void ConstructSibling(RandomListNode pHead) {
RandomListNode pre = pHead;
RandomListNode clone;
while (pre != null) {
clone = pre.next;
if (pre.random != null) {
clone.random = pre.random.next;
}
pre = clone.next;
}
}
/**
* 复制一份链表.<br>
* 将链表中的每一个节点在自己的后面复制一个<br>
* 原链表:1234 复制之后:11223344
*
* @param pHead
*/
private void CloneList(RandomListNode pHead) {
RandomListNode current = pHead;
while (current != null) {
RandomListNode temp = new RandomListNode(current.label);
temp.next = current.next;
temp.random = null;
current.next = temp;
current = temp.next;
}
}
}
运行测试:
哈希:运行时间:33ms 占用内存:8916k
第二种:运行时间:25ms 占用内存:6376k
总结:
此题重在方法,更像是一种脑筋急转弯。思路对了还是比较简单的。